diff --git a/include/core/factor/factor_velocity_direction_3d.h b/include/core/factor/factor_velocity_local_direction_3d.h
similarity index 84%
rename from include/core/factor/factor_velocity_direction_3d.h
rename to include/core/factor/factor_velocity_local_direction_3d.h
index b903113f2e8790808bea4b04749f5ca74ca6c687..b66f57af4f18e43bf820af7b2894d98a743246a8 100644
--- a/include/core/factor/factor_velocity_direction_3d.h
+++ b/include/core/factor/factor_velocity_local_direction_3d.h
@@ -1,6 +1,6 @@
 
-#ifndef FACTOR_VELOCITY_DIRECTION_3D_H_
-#define FACTOR_VELOCITY_DIRECTION_3D_H_
+#ifndef FACTOR_VELOCITY_LOCAL_DIRECTION_3D_H_
+#define FACTOR_VELOCITY_LOCAL_DIRECTION_3D_H_
 
 //Wolf includes
 #include "core/factor/factor_autodiff.h"
@@ -11,21 +11,21 @@
 
 namespace wolf {
     
-WOLF_PTR_TYPEDEFS(FactorVelocityDirection3d);
+WOLF_PTR_TYPEDEFS(FactorVelocityLocalDirection3d);
 
 //class
-class FactorVelocityDirection3d: public FactorAutodiff<FactorVelocityDirection3d,1,3,4>
+class FactorVelocityLocalDirection3d: public FactorAutodiff<FactorVelocityLocalDirection3d,1,3,4>
 {
     protected:
         double min_vel_sq_norm_; // stored in squared norm for efficiency
 
     public:
-        FactorVelocityDirection3d(FeatureBasePtr _ftr_ptr,
+        FactorVelocityLocalDirection3d(FeatureBasePtr _ftr_ptr,
                                   const double& _min_vel_norm,
                                   const ProcessorBasePtr& _processor_ptr,
                                   bool _apply_loss_function,
                                   FactorStatus _status = FAC_ACTIVE) :
-                FactorAutodiff<FactorVelocityDirection3d,1,3,4>("FactorVelocityDirection3d",
+                FactorAutodiff<FactorVelocityLocalDirection3d,1,3,4>("FactorVelocityDirection3d",
                                                                 TOP_ABS,
                                                                 _ftr_ptr,
                                                                 nullptr, nullptr, nullptr, nullptr,
@@ -41,14 +41,14 @@ class FactorVelocityDirection3d: public FactorAutodiff<FactorVelocityDirection3d
             assert(abs(_ftr_ptr->getMeasurement().norm() - 1.0) < wolf::Constants::EPS && "velocity direction measurement must be normalized");
         }
 
-        ~FactorVelocityDirection3d() override = default;
+        ~FactorVelocityLocalDirection3d() override = default;
 
         template<typename T>
         bool operator ()(const T* const _v, const T* const _o, T* _residuals) const;
 };
 
 template<typename T>
-inline bool FactorVelocityDirection3d::operator ()(const T* const _v, const T* const _q, T* _residuals) const
+inline bool FactorVelocityLocalDirection3d::operator ()(const T* const _v, const T* const _q, T* _residuals) const
 {
     Eigen::Map<const Eigen::Matrix<T,3,1> > v(_v);
     Eigen::Map<const Eigen::Quaternion<T> > q(_q);
diff --git a/include/core/processor/processor_constant_velocity.h b/include/core/processor/processor_constant_velocity.h
deleted file mode 100644
index 156e9be878df5386f493e8699d12f1ea2efe1a07..0000000000000000000000000000000000000000
--- a/include/core/processor/processor_constant_velocity.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * processor_constant_velocity.h
- *
- *  Created on: Sep 6, 2021
- *      Author: joanvallve
- */
-
-#ifndef INCLUDE_CORE_PROCESSOR_PROCESSOR_CONSTANT_VELOCITY_H_
-#define INCLUDE_CORE_PROCESSOR_PROCESSOR_CONSTANT_VELOCITY_H_
-
-#include "core/processor/processor_base.h"
-
-namespace wolf
-{
-
-WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorConstantVelocity);
-
-struct ParamsProcessorConstantVelocity : public ParamsProcessorBase
-{
-        Eigen::MatrixXd cov_v_rate;
-
-        ParamsProcessorConstantVelocity() = default;
-        ParamsProcessorConstantVelocity(std::string _unique_name, const wolf::ParamsServer & _server) :
-            ParamsProcessorBase(_unique_name, _server)
-        {
-            cov_v_rate = _server.getParam<Eigen::VectorXd> (prefix + _unique_name + "/cov_rate_diagonal").asDiagonal();
-        }
-        std::string print() const override
-        {
-            return ParamsProcessorBase::print()  + "\n"
-                + "cov_v_rate: print not implemented\n";
-        }
-};
-
-WOLF_PTR_TYPEDEFS(ProcessorConstantVelocity);
-
-class ProcessorConstantVelocity : public ProcessorBase
-{
-    protected:
-        ParamsProcessorConstantVelocityPtr params_processor_;
-        FrameBasePtr last_keyframe_;
-
-    public:
-        ProcessorConstantVelocity(ParamsProcessorConstantVelocityPtr _params);
-
-        // Factory method for high level API
-        WOLF_PROCESSOR_CREATE(ProcessorConstantVelocity, ParamsProcessorConstantVelocity);
-
-        virtual ~ProcessorConstantVelocity() override;
-        void configure(SensorBasePtr _sensor) override;
-
-    protected:
-
-        /** \brief process an incoming capture NEVER CALLED
-         */
-        virtual void processCapture(CaptureBasePtr) override {};
-
-        /** \brief process an incoming key-frame: applies the motion model between consecutive keyframes
-         */
-        virtual void processKeyFrame(FrameBasePtr _keyframe_ptr, const double& _time_tolerance) override;
-
-        /** \brief trigger in capture
-         */
-        virtual bool triggerInCapture(CaptureBasePtr) const override {return false;};
-
-        /** \brief trigger in key-frame
-         */
-        virtual bool triggerInKeyFrame(FrameBasePtr _keyframe_ptr, const double& _time_tolerance) const override {return true;};
-
-        /** \brief store key frame
-        */
-        virtual bool storeKeyFrame(FrameBasePtr) override {return false;};
-
-        /** \brief store capture
-        */
-        virtual bool storeCapture(CaptureBasePtr) override {return false;};
-
-        /** \brief Vote for KeyFrame generation
-         */
-        virtual bool voteForKeyFrame() const override {return false;};
-};
-
-} /* namespace wolf */
-
-#endif /* INCLUDE_CORE_PROCESSOR_PROCESSOR_CONSTANT_VELOCITY_H_ */
diff --git a/src/processor/processor_constant_velocity.cpp b/src/processor/processor_constant_velocity.cpp
deleted file mode 100644
index dd98e0a93894b70a5966ded73a7fe5ddebb0fb47..0000000000000000000000000000000000000000
--- a/src/processor/processor_constant_velocity.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * processor_constant_velocity.cpp
- *
- *  Created on: Sep 6, 2021
- *      Author: joanvallve
- */
-
-#include "core/processor/processor_constant_velocity.h"
-
-#include "core/capture/capture_base.h"
-#include "core/feature/feature_base.h"
-#include "core/factor/factor_block_difference.h"
-
-namespace wolf
-{
-
-ProcessorConstantVelocity::ProcessorConstantVelocity(ParamsProcessorConstantVelocityPtr _params) :
-        ProcessorBase("ProcessorConstantVelocity", 0, _params),
-        params_processor_(_params),
-        last_keyframe_(nullptr)
-{
-}
-
-ProcessorConstantVelocity::~ProcessorConstantVelocity()
-{
-}
-
-void ProcessorConstantVelocity::configure(SensorBasePtr _sensor)
-{
-    assert(params_processor_->cov_v_rate.rows() == _sensor->getProblem()->getDim() && "cov_v_rate size is wrong");
-    assert(_sensor->getProblem()->getFrameStructure().find('V') != std::string::npos && "Processor only works with problems with V");
-}
-
-void ProcessorConstantVelocity::processKeyFrame(FrameBasePtr _keyframe_ptr, const double& _time_tolerance)
-{
-    // TODO: handle if _keyframe_ptr is not the newest one
-
-    // only if not null previous keyframe
-    if (last_keyframe_ and
-        _keyframe_ptr->getTimeStamp() > last_keyframe_->getTimeStamp())
-    {
-        // emplace capture
-        auto cap = CaptureBase::emplace<CaptureBase>(_keyframe_ptr, "CaptureBase",
-                                                     _keyframe_ptr->getTimeStamp(), getSensor());
-
-        double dt = _keyframe_ptr->getTimeStamp() - last_keyframe_->getTimeStamp();
-
-        // STATE BLOCK V
-        // emplace feature
-        auto fea_v = FeatureBase::emplace<FeatureBase>(cap,
-                                                       "FeatureBase",
-                                                       Eigen::VectorXd::Zero(getProblem()->getDim()),
-                                                       params_processor_->cov_v_rate * dt);
-
-        // emplace factor
-        auto fac_v = FactorBase::emplace<FactorBlockDifference>(fea_v,
-                                                                fea_v,
-                                                                last_keyframe_->getV(),
-                                                                _keyframe_ptr->getV(),
-                                                                last_keyframe_, nullptr, nullptr, nullptr,
-                                                                0, -1, 0, -1,
-                                                                shared_from_this());
-    
-        /*// STATE BLOCK P
-        // emplace feature
-        auto fea_p = FeatureBase::emplace<FeatureBase>(cap,
-                                                     "FeatureBase",
-                                                     Eigen::VectorXd::Zero(getProblem()->getDim()),
-                                                     params_processor_->cov_p_rate * dt);
-
-        // emplace factor ct vel TODO*/
-    }
-    
-    // store keyframes
-    last_keyframe_ = _keyframe_ptr;
-}
-
-} /* namespace wolf */
-
-
-// Register in the FactoryProcessor
-#include "core/processor/factory_processor.h"
-namespace wolf {
-WOLF_REGISTER_PROCESSOR(ProcessorConstantVelocity);
-WOLF_REGISTER_PROCESSOR_AUTO(ProcessorConstantVelocity);
-} // namespace wolf
-
diff --git a/src/processor/processor_fix_wing_model.cpp b/src/processor/processor_fix_wing_model.cpp
index 2fab50466750b0b6944bffc34aaca6b5eb6647e5..869bbc087dce968c50c9e49b58b8297bf6f35b4a 100644
--- a/src/processor/processor_fix_wing_model.cpp
+++ b/src/processor/processor_fix_wing_model.cpp
@@ -9,7 +9,7 @@
 
 #include "core/capture/capture_base.h"
 #include "core/feature/feature_base.h"
-#include "core/factor/factor_velocity_direction_3d.h"
+#include "core/factor/factor_velocity_local_direction_3d.h"
 
 namespace wolf
 {
@@ -44,11 +44,11 @@ void ProcessorFixWingModel::processKeyFrame(FrameBasePtr _keyframe_ptr, const do
                                                  Eigen::Matrix1d(params_processor_->angle_stdev * params_processor_->angle_stdev));
     
     // emplace factor
-    auto fac = FactorBase::emplace<FactorVelocityDirection3d>(fea,
-                                                              fea,
-                                                              params_processor_->min_vel_norm,
-                                                              shared_from_this(),
-                                                              false);
+    auto fac = FactorBase::emplace<FactorVelocityLocalDirection3d>(fea,
+                                                                   fea,
+                                                                   params_processor_->min_vel_norm,
+                                                                   shared_from_this(),
+                                                                   false);
 }
 
 } /* namespace wolf */
diff --git a/test/gtest_factor_velocity_local_direction_3d.cpp b/test/gtest_factor_velocity_local_direction_3d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6e4ba1bbd6035da368af457dfefd80a522875491
--- /dev/null
+++ b/test/gtest_factor_velocity_local_direction_3d.cpp
@@ -0,0 +1,131 @@
+#include "core/utils/utils_gtest.h"
+
+#include "core/ceres_wrapper/solver_ceres.h"
+#include "core/factor/factor_velocity_local_direction_3d.h"
+#include "core/capture/capture_odom_2d.h"
+#include "core/math/rotations.h"
+
+
+using namespace Eigen;
+using namespace wolf;
+
+// Input odometry data and covariance
+Matrix3d data_cov = 0.1*Matrix3d::Identity();
+Vector3d v_local(1.0, 0.0, 0.0);
+double angle_stdev = 0.1;
+
+// Problem and solver
+ProblemPtr problem_ptr = Problem::create("POV", 3);
+SolverCeres solver(problem_ptr);
+
+// Frame
+FrameBasePtr frm = problem_ptr->emplaceFrame(0.0, (Vector10d() << 0,0,0,0,0,0,1,1,0,0).finished());
+
+// Capture
+CaptureBase cap = CaptureBase::emplace<CaptureBase>(frm, "CaptureBase",
+                                                    frm->getTimeStamp(), nullptr);
+
+// emplace feature
+FeatureBase fea = FeatureBase::emplace<FeatureBase>(cap, "FeatureBase",
+                                                    v_local,
+                                                    Eigen::Matrix1d(angle_stdev * angle_stdev));
+
+// emplace factor
+FactorBase fac = FactorBase::emplace<FactorVelocityLocalDirection3d>(fea,
+                                                                     fea,
+                                                                     0,
+                                                                     nullptr,
+                                                                     false);
+
+TEST(FactorVelocityLocalDirection3dTest, check_tree)
+{
+    ASSERT_TRUE(problem_ptr->check(0));
+}
+
+TEST(FactorVelocityLocalDirection3dTest, fix_PO_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>();
+        x1(2) = pi2pi(x0(2) + delta(2));
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+
+        // feature & factor with delta measurement
+        auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov);
+        FactorBase::emplace<FactorVelocityLocalDirection3d>(fea1, fea1, frm0, nullptr, false, TOP_MOTION);
+
+        // Fix frm0, perturb frm1
+        frm0->fix();
+        frm1->unfix();
+        frm1->perturb(5);
+
+        // solve for frm1
+        std::string report = solver.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6);
+
+        // remove feature (and factor) for the next loop
+        fea1->remove();
+    }
+}
+
+TEST(FactorVelocityLocalDirection3dTest, fix_1_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>();
+        x1(2) = pi2pi(x0(2) + delta(2));
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+
+        // feature & factor with delta measurement
+        auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov);
+        FactorBase::emplace<FactorVelocityLocalDirection3d>(fea1, fea1, frm0, nullptr, false, TOP_MOTION);
+
+        // Fix frm1, perturb frm0
+        frm1->fix();
+        frm0->unfix();
+        frm0->perturb(5);
+
+        // solve for frm0
+        std::string report = solver.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6);
+
+        // remove feature (and factor) for the next loop
+        fea1->remove();
+    }
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/gtest_processor_fix_wing_model.cpp b/test/gtest_processor_fix_wing_model.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1dd0fba63f5ade3e1d5f2ad5c46d081d2f2c66b0
--- /dev/null
+++ b/test/gtest_processor_fix_wing_model.cpp
@@ -0,0 +1,314 @@
+
+#include "core/utils/utils_gtest.h"
+#include "core/problem/problem.h"
+#include "core/ceres_wrapper/solver_ceres.h"
+#include "core/processor/processor_fix_wing_model.h"
+
+// STL
+#include <iterator>
+#include <iostream>
+
+using namespace wolf;
+using namespace Eigen;
+
+class ProcessorFixWingModelTest : public testing::Test
+{
+    protected:
+        ProblemPtr problem;
+        SolverManagerPtr solver;
+        SensorBasePtr sensor;
+        ProcessorBasePtr processor;
+
+        virtual void SetUp()
+        {
+            // create problem
+            problem = Problem::create("POV", 3);
+
+            // create solver
+            solver = std::make_shared<SolverCeres>(problem);
+
+            // Emplace sensor
+            sensor = SensorBase::emplace<SensorBase>(problem->getHardware(),
+                                                     "SensorBase",
+                                                     std::make_shared<StateBlock>(Vector3d::Zero()),
+                                                     std::make_shared<StateQuaternion>((Vector4d() << 0,0,0,1).finished()),
+                                                     nullptr,
+                                                     2);
+
+            // Emplace processor
+            ParamsProcessorFixWingModelPtr params = std::make_shared<ParamsProcessorFixWingModel>();
+            params->velocity_local = (Vector3d() << 1, 0, 0).finished();
+            params->angle_stdev = 0.1;
+            params->min_vel_norm = 1;
+            processor = ProcessorBase::emplace<ProcessorFixWingModel>(sensor, params);
+        }
+
+        FrameBasePtr emplaceFrame(TimeStamp ts, const Vector10d& x)
+        {
+            // new frame
+            return problem->emplaceFrame(ts, x);
+        }
+};
+
+TEST_F(ProcessorFixWingModelTest, setup)
+{
+    EXPECT_TRUE(problem->check());
+}
+
+TEST_F(ProcessorFixWingModelTest, frame_stored)
+{
+    // new frame
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    EXPECT_EQ(processor->getNStoredFrames(), 1);
+    EXPECT_EQ(processor->getNStoredCaptures(), 0);
+}
+
+TEST_F(ProcessorFixWingModelTest, capture_stored)
+{
+    // new capture
+    auto cap1 = createCapture(1);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 1);
+}
+
+TEST_F(ProcessorFixWingModelTest, captureCallbackCase1)
+{
+    // emplace frame and capture
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+    auto cap1 = emplaceCapture(frm1);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    EXPECT_EQ(cap1->getFeatureList().size(), 1); // capture processed by the processor
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 0);
+}
+
+TEST_F(ProcessorFixWingModelTest, captureCallbackCase2)
+{
+    // new frame
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+
+    // new capture
+    auto cap1 = createCapture(1);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    EXPECT_EQ(cap1->getFrame(), frm1); // capture processed by the processor
+    EXPECT_EQ(cap1->getFeatureList().size(), 1); // capture processed by the processor
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 0);
+}
+
+TEST_F(ProcessorFixWingModelTest, captureCallbackCase3)
+{
+    // new frame
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+    // new capture
+    auto cap1 = createCapture(2);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    EXPECT_TRUE(cap1->getFrame() == nullptr);
+    EXPECT_EQ(cap1->getFeatureList().size(), 0);
+    EXPECT_EQ(processor->getNStoredFrames(), 1);
+    EXPECT_EQ(processor->getNStoredCaptures(), 1);
+}
+
+TEST_F(ProcessorFixWingModelTest, keyFrameCallbackCase1)
+{
+    // emplace frame and capture
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+    auto cap1 = emplaceCapture(frm1);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    EXPECT_EQ(cap1->getFeatureList().size(), 1); // capture processed by the processor
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 0);
+}
+
+TEST_F(ProcessorFixWingModelTest, keyFrameCallbackCase2)
+{
+    // new frame
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+    // new capture
+    auto cap1 = createCapture(1);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    EXPECT_EQ(cap1->getFrame(), frm1); // capture processed by the processor
+    EXPECT_EQ(cap1->getFeatureList().size(), 1); // capture processed by the processor
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 0);
+}
+
+TEST_F(ProcessorFixWingModelTest, keyFrameCallbackCase3)
+{
+    // new frame
+    auto frm1 = emplaceFrame(2, Vector3d::Zero());
+    // new capture
+    auto cap1 = createCapture(1);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    EXPECT_TRUE(cap1->getFrame() == nullptr);
+    EXPECT_EQ(cap1->getFeatureList().size(), 0);
+    EXPECT_EQ(processor->getNStoredFrames(), 1);
+    EXPECT_EQ(processor->getNStoredCaptures(), 1);
+}
+
+TEST_F(ProcessorFixWingModelTest, keyFrameCallbackCase4)
+{
+    // new frame
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+    // new capture
+    auto cap1 = createCapture(2);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+
+    EXPECT_TRUE(cap1->getFrame() == nullptr);
+    EXPECT_EQ(cap1->getFeatureList().size(), 0);
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 1);
+}
+
+TEST_F(ProcessorFixWingModelTest, captureCallbackMatch)
+{
+    // new frame
+    auto frm1 = emplaceFrame(1, Vector3d::Zero());
+    auto frm2 = emplaceFrame(2, Vector3d::Zero());
+    auto frm3 = emplaceFrame(3, Vector3d::Zero());
+    auto frm4 = emplaceFrame(4, Vector3d::Zero());
+    auto frm5 = emplaceFrame(5, Vector3d::Zero());
+    // new captures
+    auto cap4 = createCapture(4);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm1, nullptr, 0.5);
+    problem->keyFrameCallback(frm2, nullptr, 0.5);
+    problem->keyFrameCallback(frm3, nullptr, 0.5);
+    problem->keyFrameCallback(frm4, nullptr, 0.5);
+    problem->keyFrameCallback(frm5, nullptr, 0.5);
+
+    // captureCallback
+    processor->captureCallback(cap4);
+
+    EXPECT_EQ(frm1->getCaptureList().size(), 0);
+    EXPECT_EQ(frm2->getCaptureList().size(), 0);
+    EXPECT_EQ(frm3->getCaptureList().size(), 0);
+    EXPECT_EQ(frm4->getCaptureList().size(), 1);
+    EXPECT_EQ(frm5->getCaptureList().size(), 0);
+
+    EXPECT_TRUE(cap4->getFrame() == frm4);
+    EXPECT_EQ(cap4->getFeatureList().size(), 1);
+
+    EXPECT_EQ(processor->getNStoredFrames(), 1); // all oldest frames are removed from buffer
+    EXPECT_EQ(processor->getNStoredCaptures(), 0);
+}
+
+TEST_F(ProcessorFixWingModelTest, keyFrameCallbackMatch)
+{
+    // new frame
+    auto frm2 = emplaceFrame(2, Vector3d::Zero());
+    // new captures
+    auto cap1 = createCapture(1);
+    auto cap2 = createCapture(2);
+    auto cap3 = createCapture(3);
+    auto cap4 = createCapture(4);
+    auto cap5 = createCapture(5);
+
+    // captureCallback
+    processor->captureCallback(cap1);
+    processor->captureCallback(cap2);
+    processor->captureCallback(cap3);
+    processor->captureCallback(cap4);
+    processor->captureCallback(cap5);
+
+    // keyframecallback
+    problem->keyFrameCallback(frm2, nullptr, 0.5);
+
+    EXPECT_TRUE(cap1->getFrame() == nullptr);
+    EXPECT_TRUE(cap2->getFrame() == frm2);
+    EXPECT_TRUE(cap3->getFrame() == nullptr);
+    EXPECT_TRUE(cap4->getFrame() == nullptr);
+    EXPECT_TRUE(cap5->getFrame() == nullptr);
+
+    EXPECT_EQ(cap1->getFeatureList().size(), 0);
+    EXPECT_EQ(cap2->getFeatureList().size(), 1);
+    EXPECT_EQ(cap3->getFeatureList().size(), 0);
+    EXPECT_EQ(cap4->getFeatureList().size(), 0);
+    EXPECT_EQ(cap5->getFeatureList().size(), 0);
+
+    EXPECT_EQ(processor->getNStoredFrames(), 0);
+    EXPECT_EQ(processor->getNStoredCaptures(), 4);
+}
+
+TEST_F(ProcessorFixWingModelTest, emplaceFactors)
+{
+    // emplace frame and capture
+    auto cap1 = emplaceCapture(emplaceFrame(1, Vector3d::Zero()));
+    processor->captureCallback(cap1);
+
+    auto cap2 = emplaceCapture(emplaceFrame(2, Vector3d::Ones()));
+    processor->captureCallback(cap2);
+
+    auto cap3 = emplaceCapture(emplaceFrame(3, 2*Vector3d::Ones()));
+    processor->captureCallback(cap3);
+
+    auto cap4 = emplaceCapture(emplaceFrame(4, Vector3d::Zero()));
+    processor->captureCallback(cap4);
+
+    EXPECT_EQ(cap1->getFrame()->getConstrainedByList().size(), 1);
+    EXPECT_EQ(cap2->getFrame()->getConstrainedByList().size(), 0);
+    EXPECT_EQ(cap3->getFrame()->getConstrainedByList().size(), 0);
+    EXPECT_EQ(cap4->getFrame()->getConstrainedByList().size(), 0);
+
+    EXPECT_EQ(cap1->getFeatureList().size(), 1);
+    EXPECT_EQ(cap2->getFeatureList().size(), 1);
+    EXPECT_EQ(cap3->getFeatureList().size(), 1);
+    EXPECT_EQ(cap4->getFeatureList().size(), 1);
+
+    EXPECT_EQ(cap1->getFeatureList().front()->getFactorList().size(), 0);
+    EXPECT_EQ(cap2->getFeatureList().front()->getFactorList().size(), 0);
+    EXPECT_EQ(cap3->getFeatureList().front()->getFactorList().size(), 0);
+    EXPECT_EQ(cap4->getFeatureList().front()->getFactorList().size(), 1);
+
+    EXPECT_EQ(cap1->getFrame()->getConstrainedByList().front(), cap4->getFeatureList().front()->getFactorList().front());
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}