diff --git a/include/core/problem/problem.h b/include/core/problem/problem.h
index 004ba29b696bab7d8d3298ef702e08eb06d2c738..4f521c1155b33c1ab5afbf3aab67a3b38312dfd5 100644
--- a/include/core/problem/problem.h
+++ b/include/core/problem/problem.h
@@ -271,6 +271,9 @@ class Problem : public std::enable_shared_from_this<Problem>
         // Zero state provider
         Eigen::VectorXd zeroState ( ) const;
         bool priorIsSet() const;
+        // Perturb state
+        void            perturb(double amplitude = 0.01);
+
 
         // Map branch -----------------------------------------
         MapBasePtr getMap() const;
diff --git a/include/core/sensor/sensor_base.h b/include/core/sensor/sensor_base.h
index 676a83bc5c9ade574e1b10b2a21a6bf2740cd3cd..1c099cb9be4827705bd43d229714ea1dabf24ed0 100644
--- a/include/core/sensor/sensor_base.h
+++ b/include/core/sensor/sensor_base.h
@@ -181,6 +181,9 @@ class SensorBase : public NodeBase, public HasStateBlocks, public std::enable_sh
         StateBlockPtr getStateBlockDynamic(const char _key) const { return getStateBlockDynamic(std::string(1,_key)); }
         StateBlockPtr getStateBlockDynamic(const char _key, const TimeStamp& _ts) const { return getStateBlockDynamic(std::string(1,_key), _ts); }
 
+        // Declare a state block as dynamic or static (with _dymanic = false)
+        void setStateBlockDynamic(const std::string& _key, bool _dynamic = true);
+
         bool isStateBlockDynamic(const std::string& _key) const;
         bool isStateBlockInCapture(const std::string& _key, const TimeStamp& _ts, CaptureBasePtr& _cap) const;
         bool isStateBlockInCapture(const std::string& _key, CaptureBasePtr& _cap) const;
@@ -197,7 +200,6 @@ class SensorBase : public NodeBase, public HasStateBlocks, public std::enable_sh
     protected:
         void removeStateBlocks();
         virtual void registerNewStateBlocks() const;
-        void setStateBlockDynamic(const std::string& _key, bool _dynamic = true);
 
     public:
 
diff --git a/include/core/state_block/has_state_blocks.h b/include/core/state_block/has_state_blocks.h
index 0f7d13f99c2af92d8779c11a7e705bb4ef94f99f..ef55d163be4764393c4e1b08ac0003ae67b1d223 100644
--- a/include/core/state_block/has_state_blocks.h
+++ b/include/core/state_block/has_state_blocks.h
@@ -68,6 +68,10 @@ class HasStateBlocks
         unsigned int    getSize() const;
         unsigned int    getLocalSize() const;
 
+        // Perturb state
+        void            perturb(double amplitude = 0.01);
+
+
     private:
         std::string structure_;
         std::unordered_map<std::string, StateBlockPtr> state_block_map_;
@@ -251,6 +255,5 @@ inline unsigned int HasStateBlocks::getLocalSize() const
     return size;
 }
 
-
 } // namespace wolf
 #endif /* STATE_BLOCK_HAS_STATE_BLOCKS_H_ */
diff --git a/include/core/state_block/state_block.h b/include/core/state_block/state_block.h
index b68b4ad7dd482f071faf04339656879635232dd2..33aa6fcb4b221ea1dc23f24b21f4a0fb12cbfc0d 100644
--- a/include/core/state_block/state_block.h
+++ b/include/core/state_block/state_block.h
@@ -142,6 +142,10 @@ public:
          **/
         void resetLocalParamUpdated();
 
+        /** \brief perturb state
+         */
+        void perturb(double amplitude = 0.1);
+
         /** \brief Add this state_block to the problem
          **/
         //void addToProblem(ProblemPtr _problem_ptr);
diff --git a/src/capture/capture_base.cpp b/src/capture/capture_base.cpp
index fbb54972b09b78f0a0e6a6e66701396a481d9cfc..54e5d2a3cdedb301a7580e691cad9543df3c24c2 100644
--- a/src/capture/capture_base.cpp
+++ b/src/capture/capture_base.cpp
@@ -140,7 +140,7 @@ const std::string& CaptureBase::getStructure() const
 
 StateBlockPtr CaptureBase::getStateBlock(const std::string& _key) const
 {
-    if (getSensor() and getSensor()->getStateBlock(_key))
+    if (getSensor() and getSensor()->hasStateBlock(_key))
     {
         if (getSensor()->isStateBlockDynamic(_key))
             return HasStateBlocks::getStateBlock(_key);
diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp
index a5576fb3c0fc1524b6721405c69ed5c2ce22ec8c..855236ece07f90a1570d293ac5c9333ee445658c 100644
--- a/src/problem/problem.cpp
+++ b/src/problem/problem.cpp
@@ -1386,6 +1386,26 @@ std::string Problem::printToString(int depth, bool constr_by, bool metric, bool
     result << endl;
     return result.str();
 }
+
+void Problem::perturb(double amplitude)
+{
+    // Sensors
+    for (auto& S : getHardware()->getSensorList())
+        S->perturb(amplitude);
+
+    // Frames and Captures
+    for (auto& F : getTrajectory()->getFrameList())
+    {
+        F->perturb(amplitude);
+        for (auto& C : F->getCaptureList())
+            C->perturb(amplitude);
+    }
+
+    // Landmarks
+    for (auto& L : getMap()->getLandmarkList())
+        L->perturb(amplitude);
+}
+
 bool Problem::check(int verbose_level) const
 {
     using std::cout;
diff --git a/src/state_block/has_state_blocks.cpp b/src/state_block/has_state_blocks.cpp
index 8b11f1cb3981206700b4ce54ad5529df54ae6d29..83cf44b26bdfcad7e415633ef6d8fe783564a75c 100644
--- a/src/state_block/has_state_blocks.cpp
+++ b/src/state_block/has_state_blocks.cpp
@@ -44,5 +44,14 @@ void HasStateBlocks::removeStateBlocks(ProblemPtr _problem)
     }
 }
 
+void HasStateBlocks::perturb(double amplitude)
+{
+    for (const auto& pair_key_sb : state_block_map_)
+    {
+        auto& sb = pair_key_sb.second;
+        if (!sb->isFixed())
+            sb->perturb(amplitude);
+    }
+}
 
 }
diff --git a/src/state_block/state_block.cpp b/src/state_block/state_block.cpp
index f582ae97787b4a3df8d1e98177385427580a90c0..783a56a5e8cb52fe0ae79e2ad14ca4b50976a48c 100644
--- a/src/state_block/state_block.cpp
+++ b/src/state_block/state_block.cpp
@@ -36,4 +36,22 @@ void StateBlock::setFixed(bool _fixed)
 //    _problem_ptr->removeStateBlock(shared_from_this());
 //}
 
+void StateBlock::perturb(double amplitude)
+{
+    using namespace Eigen;
+    VectorXd perturbation(VectorXd::Random(getLocalSize()) * amplitude);
+    if (local_param_ptr_ == nullptr)
+        state_ += perturbation;
+    else
+    {
+        VectorXd state_perturbed(getSize());
+        // Note: LocalParametrizationBase::plus() works with Eigen::Map only. Build all necessary maps:
+        Map<const VectorXd> state_map(state_.data(), getSize());
+        Map<const VectorXd> perturbation_map(perturbation.data(), getLocalSize());
+        Map<VectorXd> state_perturbed_map(state_perturbed.data(), getSize());
+        local_param_ptr_->plus(state_map, perturbation_map, state_perturbed_map);
+        state_ = state_perturbed;
+    }
+}
+
 }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 10a1f9ab0d5d3b43699b098ef0d7f2bf072990fb..d32d5c6216c857ad703c34aa1a10f4b29d6c4dc0 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -137,6 +137,10 @@ target_link_libraries(gtest_shared_from_this ${PROJECT_NAME})
 wolf_add_gtest(gtest_solver_manager gtest_solver_manager.cpp)
 target_link_libraries(gtest_solver_manager ${PROJECT_NAME})
 
+# StateBlock class test
+wolf_add_gtest(gtest_state_block gtest_state_block.cpp)
+target_link_libraries(gtest_state_block ${PROJECT_NAME})
+
 # TimeStamp class test
 wolf_add_gtest(gtest_time_stamp gtest_time_stamp.cpp)
 target_link_libraries(gtest_time_stamp ${PROJECT_NAME})
diff --git a/test/gtest_problem.cpp b/test/gtest_problem.cpp
index 40e354ddfef4e98746fc7d3bd5c6e0ca983a3d93..e0ba9a42a17936b62ec329c1fb022052d5ae6c30 100644
--- a/test/gtest_problem.cpp
+++ b/test/gtest_problem.cpp
@@ -16,6 +16,11 @@
 #include "dummy/processor_tracker_feature_dummy.h"
 #include "core/solver/solver_manager.h"
 
+#include "core/sensor/sensor_diff_drive.h"
+#include "core/processor/processor_diff_drive.h"
+#include "core/capture/capture_diff_drive.h"
+#include "core/state_block/state_quaternion.h"
+
 #include <iostream>
 
 using namespace wolf;
@@ -318,6 +323,96 @@ TEST(Problem, Covariances)
 
 }
 
+TEST(Problem, perturb)
+{
+    auto problem = Problem::create("PO", 2);
+
+    // make a sensor first
+    auto intr = std::make_shared<ParamsSensorDiffDrive>();
+    intr->radius_left                   = 1.0;
+    intr->radius_right                  = 1.0;
+    intr->wheel_separation              = 1.0;
+    intr->ticks_per_wheel_revolution    = 100;
+    Vector3d extr(0,0,0);
+    auto sensor = std::static_pointer_cast<SensorDiffDrive>(problem->installSensor("SensorDiffDrive", "sensor diff drive", extr, intr));
+    sensor->setStateBlockDynamic("I", true);
+
+    Vector3d pose; pose << 0,0,0;
+
+    int i = 0;
+    for (TimeStamp t = 0.0; t < 2.0; t += 1.0)
+    {
+        auto F = problem->emplaceFrame(KEY, pose, t);
+        if (i==0) F->fix();
+
+        for (int j = 0; j< 2 ; j++)
+        {
+            auto sb     = std::make_shared<StateBlock>(Vector3d(1,1,1));
+            auto cap    = CaptureBase::emplace<CaptureBase>(F, "CaptureBase", t, sensor, nullptr, nullptr, sb);
+        }
+        i++;
+    }
+
+    for (int l = 0; l < 2; l++)
+    {
+        auto sb1    = std::make_shared<StateBlock>(Vector2d(1,2));
+        auto sb2    = std::make_shared<StateBlock>(Vector1d(3));
+        auto L      = LandmarkBase::emplace<LandmarkBase>(problem->getMap(), "LandmarkBase", sb1, sb2);
+        if (l==0) L->fix();
+    }
+
+    /// PRINT, PERTURB, AND PRINT AGAIN
+    problem->print(2,0,1,1);
+
+    problem->perturb(0.2);
+
+    problem->print(2,0,1,1);
+
+
+    //// CHECK ALL STATE BLOCKS ///
+
+    double prec = 1e-2;
+
+    for (auto S : problem->getHardware()->getSensorList())
+    {
+        ASSERT_TRUE (S->getP()->getState().isApprox(Vector2d(0,0), prec) );
+        ASSERT_TRUE (S->getO()->getState().isApprox(Vector1d(0), prec) );
+        ASSERT_FALSE(S->getIntrinsic()->getState().isApprox(Vector3d(1,1,1), prec) );
+    }
+
+    for (auto F : problem->getTrajectory()->getFrameList())
+    {
+        if (F->isFixed()) // fixed
+        {
+            ASSERT_TRUE (F->getP()->getState().isApprox(Vector2d(0,0), prec) );
+            ASSERT_TRUE (F->getO()->getState().isApprox(Vector1d(0), prec) );
+        }
+        else
+        {
+            ASSERT_FALSE(F->getP()->getState().isApprox(Vector2d(0,0), prec) );
+            ASSERT_FALSE(F->getO()->getState().isApprox(Vector1d(0), prec) );
+        }
+        for (auto C : F->getCaptureList())
+        {
+            // all are estimated
+            ASSERT_FALSE(C->getSensorIntrinsic()->getState().isApprox(Vector3d(1,1,1), prec) );
+        }
+    }
+    for (auto L : problem->getMap()->getLandmarkList())
+    {
+        if ( L->isFixed() ) // fixed
+        {
+            ASSERT_TRUE (L->getP()->getState().isApprox(Vector2d(1,2), prec) );
+            ASSERT_TRUE (L->getO()->getState().isApprox(Vector1d(3), prec) );
+        }
+        else
+        {
+            ASSERT_FALSE(L->getP()->getState().isApprox(Vector2d(1,2), prec) );
+            ASSERT_FALSE(L->getO()->getState().isApprox(Vector1d(3), prec) );
+        }
+    }
+}
+
 int main(int argc, char **argv)
 {
   testing::InitGoogleTest(&argc, argv);
diff --git a/test/gtest_state_block.cpp b/test/gtest_state_block.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..19d9e3cf63623ef275ee5f8fc8111f4e88ece4d1
--- /dev/null
+++ b/test/gtest_state_block.cpp
@@ -0,0 +1,69 @@
+/*
+ * gtest_state_block.cpp
+ *
+ *  Created on: Mar 31, 2020
+ *      Author: jsola
+ */
+
+#include "core/utils/utils_gtest.h"
+#include "core/utils/logging.h"
+
+#include "core/state_block/state_block.h"
+#include "core/state_block/state_quaternion.h"
+#include "core/state_block/state_angle.h"
+
+#include <iostream>
+
+
+using namespace Eigen;
+using namespace std;
+using namespace wolf;
+
+TEST(StateBlock, block_perturb)
+{
+    Vector3d x(10,20,30);
+    StateBlock sb(x);
+
+    sb.perturb(0.5);
+
+    WOLF_INFO("original ", x.transpose(), ", perturbed = ", sb.getState().transpose());
+
+    ASSERT_NE(x.norm(), sb.getState().norm());
+    ASSERT_MATRIX_APPROX(x , sb.getState() , 0.5 * 4); // 4-sigma test...
+}
+
+TEST(StateBlock, angle_perturb)
+{
+    Vector1d x(1.0);
+    StateAngle sb(x(0));
+
+    sb.perturb(0.1);
+
+    WOLF_INFO("original ", x.transpose(), ", perturbed = ", sb.getState().transpose());
+
+    ASSERT_NE(x.norm(), sb.getState().norm());
+    ASSERT_MATRIX_APPROX(x , sb.getState() , 0.1 * 4); // 4-sigma test...
+}
+
+TEST(StateBlock, quaternion_perturb)
+{
+    Vector4d x(0.5,0.5,0.5,0.5);
+    StateQuaternion sb(x);
+
+    sb.perturb(0.01);
+
+    WOLF_INFO("original ", x.transpose(), ", perturbed = ", sb.getState().transpose());
+
+    ASSERT_LT((sb.getState().transpose() * x).norm() , 1.0); // quaternions are not parallel ==> not equal
+    ASSERT_MATRIX_APPROX(x , sb.getState() , 0.01 * 4); // 4-sigma test...
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
+
+
+