{"id":14992222,"url":"https://github.com/wangxiaochuTHU/yakf","last_synced_at":"2025-09-25T14:30:59.016Z","repository":{"id":41170246,"uuid":"503216740","full_name":"wangxiaochuTHU/yakf","owner":"wangxiaochuTHU","description":"Yet Another Kalman Filter Implementation.  As well as Lie Theory (Lie group and algebra) on SE(3).  [no_std] is supported by default.","archived":false,"fork":false,"pushed_at":"2022-07-15T15:07:33.000Z","size":138,"stargazers_count":18,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-18T07:49:47.605Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wangxiaochuTHU.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-14T05:11:01.000Z","updated_at":"2024-02-23T22:30:28.000Z","dependencies_parsed_at":"2022-08-10T01:42:57.223Z","dependency_job_id":null,"html_url":"https://github.com/wangxiaochuTHU/yakf","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wangxiaochuTHU/yakf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangxiaochuTHU%2Fyakf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangxiaochuTHU%2Fyakf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangxiaochuTHU%2Fyakf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangxiaochuTHU%2Fyakf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wangxiaochuTHU","download_url":"https://codeload.github.com/wangxiaochuTHU/yakf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangxiaochuTHU%2Fyakf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276932091,"owners_count":25730722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-25T02:00:09.612Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T15:00:52.455Z","updated_at":"2025-09-25T14:30:58.740Z","avatar_url":"https://github.com/wangxiaochuTHU.png","language":"Rust","funding_links":[],"categories":["Signal Processing"],"sub_categories":[],"readme":"# yakf - Yet Another Kalman Filter\nYet Another Kalman Filter Implementation, as well as, \n\nLie Theory (Lie group, algebra, vector) on SO(3), SE(3), SO(2), and SE(2).\n\n`[no_std]` is supported by default.\n\n# Current implementation status\n\n## Filter Status\n* UKF ✅ \n* EKF (Only dynamically-sized version) ✅ \n\n## Sampling Method Status\n* Minimal Skew Simplex Sampling (n+2) ✅\n* Symmetrically-Distributed Sampling Method (2n+1) ✅\n\n## Static V.S Dynamic Cases\n* For ***statically***-sized state whose dimension is known in compile time, refer to `yakf::filters`\n* For ***dynamically***-sized state whose dimension may vary in run time, refer to `yakf::dfilters`\n\n## Lie Group Status\n* SO(3) ✅, refer to `yakf::lie::so3`\n* SE(3) ✅, refer to `yakf::lie::se3`\n* SO(2) ✅, refer to `yakf::lie::so2`\n* SE(2) ✅, refer to `yakf::lie::se2`\n\n## Lie Group Examples\n* (non-generic) Kalman Filter Example on SO(3) ✅ see `examples/so3_kf.rs` for instance\n* (non-generic) Kalman Filter Example on SE(3) ✅ see `examples/se3_kf.rs` for instance\n\n\n***NOTE that some functions havn't been thoroughly tested, so please let me know if there is any error.***\n\n# UKF Usage\nAdd this to your Cargo.toml:\n```\n[dependencies]\nyakf = \"0.1\"\n```\n\nExample (statically-sized):\n```\n/// import yakf crate\nextern crate yakf;\n/// import State trait, UKF filter struct, and MSSS sampling method struct\nuse yakf::kf::{\n    MinimalSkewSimplexSampling as MSSS, State, SymmetricallyDistributedSampling as SDS, UKF,\n};\n\n/// import Re-exports of hifitime (for time) and nalgebra (for matrix)\nuse yakf::{\n    linalg,\n    time::{Duration, Epoch, Unit},\n};\n\nfn main() {\n    use crate::linalg::{Const, OMatrix, OVector, U2};\n    use rand::prelude::*;\n\n    #[derive(Debug)]\n    /// define a custom struct to be the state. e.g., BikeState, has a 2-D vector x (x[0]: position, x[1]: velocity) and a timestamped time t.\n    pub struct BikeState {\n        pub x: OVector\u003cf64, U2\u003e,\n        pub t: Epoch,\n    }\n\n    /// for example, you can define your own methods.\n    impl BikeState {\n        pub fn new(state: OVector\u003cf64, U2\u003e, epoch: Epoch) -\u003e Self {\n            BikeState { x: state, t: epoch }\n        }\n        pub fn zeros() -\u003e Self {\n            Self {\n                x: OVector::\u003cf64, U2\u003e::zeros(),\n                t: Epoch::from_gregorian_tai(2022, 5, 10, 0, 0, 0, 0),\n            }\n        }\n    }\n\n    /// you **MUST** implement State\u003cT,U\u003e for your custom state struct.\n    ///\n    impl State\u003cU2, Const\u003c1\u003e\u003e for BikeState {\n        fn state(\u0026self) -\u003e \u0026OVector\u003cf64, U2\u003e {\n            \u0026self.x\n        }\n        fn set_state(\u0026mut self, state: OVector\u003cf64, U2\u003e) {\n            self.x = state;\n        }\n\n        fn epoch(\u0026self) -\u003e Epoch {\n            self.t\n        }\n        fn set_epoch(\u0026mut self, epoch: Epoch) {\n            self.t = epoch;\n        }\n    }\n    // you SHOULD provide a function `dynamics` for UKF propagating the state.\n    //\n    // for example,\n    let dynamics = |x: \u0026OVector\u003cf64, U2\u003e, _ext: \u0026OVector\u003cf64, Const\u003c1\u003e\u003e, dt: Duration| {\n        OVector::\u003cf64, U2\u003e::new(x[0] + x[1] * dt.in_seconds(), x[1])\n    };\n\n    // you SHOULD ALSO provide a function for UKF yielding measurements based on given state.\n    //\n    // for example, assume the measuring has a 2-D measurement.\n    let measure_model = |x: \u0026OVector\u003cf64, U2\u003e| OVector::\u003cf64, U2\u003e::new(x[0], x[1]);\n\n    // you SHOULD ALSO specify a sampling method for UKF.\n    // for example, you can specify a MSSS method\n    type T2 = Const\u003c4\u003e;\n    let samling_method = MSSS::\u003cU2, T2\u003e::build(0.6).unwrap();\n\n    // or you can specify a SDS method as an alternative.\n    type _T2 = Const\u003c5\u003e;\n\n    let _samling_method = SDS::\u003cU2, _T2\u003e::build(1e-3, None, None).unwrap();\n\n    // finally, build the UKF.\n    let mut ukf = UKF::\u003cU2, T2, U2, Const\u003c1\u003e, BikeState\u003e::build(\n        Box::new(dynamics),\n        Box::new(measure_model),\n        Box::new(samling_method),\n        BikeState::zeros(),\n        OMatrix::\u003cf64, U2, U2\u003e::from_diagonal_element(10.0),\n        OMatrix::\u003cf64, U2, U2\u003e::from_diagonal_element(1.0),\n        OMatrix::\u003cf64, U2, U2\u003e::from_diagonal(\u0026OVector::\u003cf64, U2\u003e::new(1.0, 0.001)),\n    );\n\n    // you can then use ukf to estimate the state vector.\n\n    let mut rng = rand::thread_rng();\n    let mut add_noisies = |mut y: OVector\u003cf64, U2\u003e| {\n        y[0] += rng.gen_range(-3.0..3.0);\n        y[1] += rng.gen_range(-0.1..0.1);\n        y\n    };\n    let s = OVector::\u003cf64, U2\u003e::new(-5.0, 1.0);\n    let t = Epoch::now().unwrap();\n    let mut bike_actual = BikeState::new(s, t);\n\n    println!(\n        \"bike actual = {:?}, ukf estimate = {:?}\",\n        \u0026bike_actual,\n        \u0026ukf.current_estimate()\n    );\n    let mut actual_normed_noise: Vec\u003cf64\u003e = Vec::new();\n    let mut estimate_normed_error: Vec\u003cf64\u003e = Vec::new();\n    let nums_measure = 500_usize;\n\n    // you can set an arbitary time base for ukf.\n    // a timing system would help in aligning data.\n    let ukf_base_epoch = ukf.current_estimate().epoch();\n\n    for i in 0..nums_measure {\n        let dt = Duration::from_f64(1.0, Unit::Second);\n        let m_epoch = ukf_base_epoch + dt;\n\n        /*\n        Remark 1. Note that the actual dynamics doesn't need to be exactly the same with that used by ukf.\n                Actually, the dynamics used by ukf is only a Model abstracted from the actual one.\n                But in this example, assume they are the same. Case is the same for measuring model.\n\n        Remark 2. For the same reason, the delta_t used by actual dynamics is not neccesarily the same\n                with dt (the one used by ukf estimation) and, actually, delta_t should be much smaller than dt\n                in real world. However, for simplity, this example just let them be the same, i.e. delta_t = dt.\n        */\n        let _ = bike_actual.propagate(\u0026dynamics, dt, OVector::\u003cf64, Const\u003c1\u003e\u003e::zeros());\n\n        // use measuring model to simulate a measurement, and add some noises on it.\n        let mut meas = measure_model(\u0026bike_actual.state());\n        meas = add_noisies(meas);\n\n        // every time the measurement is ready, ukf is trigger to update.\n        ukf.feed_and_update(meas, m_epoch, OVector::\u003cf64, Const\u003c1\u003e\u003e::zeros());\n        if i \u003e nums_measure / 3 {\n            actual_normed_noise.push((\u0026meas - bike_actual.state()).norm());\n            estimate_normed_error\n                .push((ukf.current_estimate().state() - bike_actual.state()).norm());\n        }\n\n        println!(\n            \"bike actual = {:?}, meas = {:.3?}, ukf estimate = {:.3?}\",\n            \u0026bike_actual.state(),\n            meas,\n            \u0026ukf.current_estimate().state(),\n        );\n    }\n    let nums = actual_normed_noise.len();\n    let noise_metric: f64 = actual_normed_noise\n        .into_iter()\n        .fold(0.0, |acc, x| acc + x / nums as f64);\n    let error_metric: f64 = estimate_normed_error\n        .into_iter()\n        .fold(0.0, |acc, x| acc + x / nums as f64);\n    println!(\n        \"noise_metric = {:?}, error_metric = {:?}\",\n        noise_metric, error_metric\n    );\n    assert!(error_metric \u003c noise_metric);\n}\n\n\n\n\n```\n\nYou may see the output as\n```\n.. .. ..\nactual = [493.0, 1.0], meas = [493.281, 1.073], estimate = [492.553, 1.073]\nactual = [494.0, 1.0], meas = [492.615, 0.941], estimate = [492.598, 0.941]\nactual = [495.0, 1.0], meas = [496.849, 1.019], estimate = [495.710, 1.019]\nnoise_metric = 1.5346849337852513, error_metric = 1.2218914483371828\n```\n\n# SO(3)/SE(3) Usage\n\nThe element in SO(3) is stored as an Enum type, named by `SO3`.\nOne can create such an element by methods `from_vec`, `from_grp`, `from_alg`. Either will be Ok, since an element can be expressed in all the three forms, and there exists a one-on-one mapping relationship among them.\n\nFor example, one can create a SO3 element `so` from a 3-d vector:\n\n```\nlet so = SO3::from_vec(Vec3::new(0.3, 0.6, -0.9));\n```\nIf you want use its vector form, just call \n```\nlet v = so.to_vec();\n```\nif you want use its group form, just call \n```\nlet g = so.to_group();\n```\nand if you want use its algebra form, just call \n```\nlet a = so.to_alg();\n```\nAs you know, all `v`, `g`, `a` stand for the same `SO3` element `so` (limited in a proper range).\n\nCurrently, some neccessary methods have been implemented for `SO3`.\n\nThe design of `SE(3)` is consensus with `SO(3)`. \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FwangxiaochuTHU%2Fyakf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FwangxiaochuTHU%2Fyakf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FwangxiaochuTHU%2Fyakf/lists"}