|
|
@@ -0,0 +1,173 @@
|
|
|
+#include "core/basic_obj_types.hpp"
|
|
|
+#include "core/tristate_obj.h"
|
|
|
+#include "utility/config_utility.hpp"
|
|
|
+
|
|
|
+DEFAULT_TRISTATE_OBJ_DEF(kalman_denoiser)
|
|
|
+
|
|
|
+namespace sophiar {
|
|
|
+
|
|
|
+ using boost::asio::awaitable;
|
|
|
+
|
|
|
+ using namespace Eigen;
|
|
|
+
|
|
|
+ namespace kalman_denoiser_impl {
|
|
|
+
|
|
|
+ constexpr auto TRANS_R = 0.2;
|
|
|
+ constexpr auto TRANS_P0 = 1000;
|
|
|
+ constexpr auto ROT_R = 0.002;
|
|
|
+ constexpr auto ROT_P0 = 1;
|
|
|
+
|
|
|
+ constexpr auto TRANS_R2 = TRANS_R * TRANS_R;
|
|
|
+ constexpr auto TRANS_P02 = TRANS_P0 * TRANS_P0;
|
|
|
+ constexpr auto ROT_R2 = ROT_R * ROT_R;
|
|
|
+ constexpr auto ROT_P02 = ROT_P0 * ROT_P0;
|
|
|
+
|
|
|
+ struct simple_kalman {
|
|
|
+ double X, P, Q; // state related
|
|
|
+ double R; // parameters
|
|
|
+
|
|
|
+ double progress(double Z) {
|
|
|
+ auto X_p = X;
|
|
|
+ auto P_p = P + Q;
|
|
|
+ auto K = P_p / (P_p + R);
|
|
|
+ auto X_n = X_p + K * (Z - X_p);
|
|
|
+ auto P_n = P_p - K * P_p;
|
|
|
+ Q = (Z - X_p) * (Z - X_p);
|
|
|
+ if (Q <= R) {
|
|
|
+ Q = 0;
|
|
|
+ }
|
|
|
+ X = X_n;
|
|
|
+ P = P_n;
|
|
|
+ return X;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct transform_denoiser {
|
|
|
+ simple_kalman filters[7] = {};
|
|
|
+ double buffer[7] = {};
|
|
|
+ int iter = 0;
|
|
|
+
|
|
|
+ transform_denoiser() {
|
|
|
+ reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ void reset() {
|
|
|
+ for (auto k = 0; k < 3; ++k) {
|
|
|
+ filters[k].X = 0;
|
|
|
+ filters[k].P = TRANS_P02;
|
|
|
+ filters[k].Q = 0;
|
|
|
+ filters[k].R = TRANS_R2;
|
|
|
+ }
|
|
|
+ for (auto k = 3; k < 7; ++k) {
|
|
|
+ filters[k].X = 0;
|
|
|
+ filters[k].P = ROT_P02;
|
|
|
+ filters[k].Q = 0;
|
|
|
+ filters[k].R = ROT_R2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ transform_denoiser &operator<<(double val) {
|
|
|
+ buffer[iter] = filters[iter].progress(val);
|
|
|
+ ++iter;
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
+ transform_denoiser &operator>>(double &val) {
|
|
|
+ val = buffer[iter++];
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
+ transform_obj::pointer progress(const transform_obj::pointer &in) {
|
|
|
+ // handle empty
|
|
|
+ if (!in) {
|
|
|
+ reset();
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ // load values
|
|
|
+ iter = 0;
|
|
|
+ in->write_to(*this);
|
|
|
+
|
|
|
+ // save values
|
|
|
+ iter = 0;
|
|
|
+ auto ret = transform_obj::new_instance();
|
|
|
+ ret->fill_from(*this);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ using namespace kalman_denoiser_impl;
|
|
|
+
|
|
|
+ struct kalman_denoiser::impl {
|
|
|
+
|
|
|
+ variable_index_type var_index_in, var_index_out;
|
|
|
+ variable_type_index_type var_type;
|
|
|
+ sophiar_pool::callback_token_type cb_token = nullptr;
|
|
|
+ sophiar_pool::attach_token_type ath_token = nullptr;
|
|
|
+
|
|
|
+ transform_denoiser transform_worker;
|
|
|
+
|
|
|
+ void progress() {
|
|
|
+ switch (var_type) {
|
|
|
+ case transform_var_type_index: {
|
|
|
+ auto val = QUERY_VARIABLE(transform_obj, var_index_in);
|
|
|
+ auto val_n = transform_worker.progress(val);
|
|
|
+ UPDATE_VARIABLE(transform_obj, var_index_out, val_n);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ assert(false);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void load_config(const nlohmann::json &config) {
|
|
|
+ // input
|
|
|
+ auto var_name_in = LOAD_STRING_ITEM("variable_in");
|
|
|
+ auto var_info_in = global_sophiar_pool->query_variable_information(var_name_in);
|
|
|
+ var_index_in = var_info_in.index;
|
|
|
+
|
|
|
+ // output
|
|
|
+ auto var_name_out = LOAD_STRING_ITEM("variable_out");
|
|
|
+ auto var_info_out = global_sophiar_pool->query_variable_information(var_name_out);
|
|
|
+ var_index_out = var_info_out.index;
|
|
|
+
|
|
|
+ assert(var_info_in.type_index == var_info_out.type_index);
|
|
|
+ var_type = var_info_in.type_index;
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ kalman_denoiser::kalman_denoiser()
|
|
|
+ : pimpl(std::make_unique<impl>()) {}
|
|
|
+
|
|
|
+ kalman_denoiser::~kalman_denoiser() = default;
|
|
|
+
|
|
|
+ awaitable<bool> kalman_denoiser::on_init(const nlohmann::json &config) noexcept {
|
|
|
+ pimpl->load_config(config);
|
|
|
+ assert(pimpl->cb_token == nullptr);
|
|
|
+ pimpl->cb_token = REGISTER_CALLBACK([this] { pimpl->progress(); });
|
|
|
+ co_return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ awaitable<bool> kalman_denoiser::on_start(const nlohmann::json &) noexcept {
|
|
|
+ assert(pimpl->ath_token == nullptr);
|
|
|
+ pimpl->ath_token = ATTACH_CALLBACK(pimpl->var_index_in, pimpl->cb_token);
|
|
|
+ co_return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ awaitable<void> kalman_denoiser::on_stop() noexcept {
|
|
|
+ DETACH_CALLBACK(pimpl->ath_token);
|
|
|
+ pimpl->ath_token = nullptr;
|
|
|
+ co_return;
|
|
|
+ }
|
|
|
+
|
|
|
+ awaitable<void> kalman_denoiser::on_reset() noexcept {
|
|
|
+ UNREGISTER_CALLBACK(pimpl->cb_token);
|
|
|
+ pimpl->cb_token = nullptr;
|
|
|
+ co_return;
|
|
|
+ }
|
|
|
+}
|