diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 484793812a146123926cfcc6388184c8b822743a..efb89ade080ff6f322fca52d4476587f1578f894 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -148,6 +148,10 @@ ENDIF(vision_utils_FOUND)
 wolf_add_gtest(gtest_constraint_gnss_fix_2D gtest_constraint_gnss_fix_2D.cpp)
 target_link_libraries(gtest_constraint_gnss_fix_2D ${PROJECT_NAME})
 
+# ConstraintGnssFix2D test
+wolf_add_gtest(gtest_constraint_gnss_fix_2D_simple gtest_constraint_gnss_fix_2D_simple.cpp)
+target_link_libraries(gtest_constraint_gnss_fix_2D_simple ${PROJECT_NAME})
+
 # ConstraintGnssSingleDiff2D test
 wolf_add_gtest(gtest_constraint_gnss_single_diff_2D gtest_constraint_gnss_single_diff_2D.cpp)
 target_link_libraries(gtest_constraint_gnss_single_diff_2D ${PROJECT_NAME})
diff --git a/test/gtest_constraint_gnss_fix_2D_simple.cpp b/test/gtest_constraint_gnss_fix_2D_simple.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cc2f349820156f8d70208a32b6780bbd770ef5bb
--- /dev/null
+++ b/test/gtest_constraint_gnss_fix_2D_simple.cpp
@@ -0,0 +1,367 @@
+/**
+ * \file gtest_constraint_gnss_fix_2D.cpp
+ *
+ *  Created on: Aug 1, 2018
+ *      \author: jvallve
+ */
+
+
+#include "base/constraint/constraint_gnss_fix_2D.h"
+#include "utils_gtest.h"
+
+#include "base/problem.h"
+#include "base/sensor/sensor_gnss.h"
+#include "base/processor/processor_gnss_fix.h"
+
+#include "base/ceres_wrapper/ceres_manager.h"
+
+
+using namespace Eigen;
+using namespace wolf;
+
+void resetStates(SensorGnssPtr gnss_sensor_ptr, FrameBasePtr frame_ptr,
+                 const Vector1s& o_enu_map,
+                 const Vector3s& t_base_antena,
+                 const Vector3s& t_enu_map,
+                 const Vector3s& t_map_base,
+                 const Vector1s& o_map_base)
+{
+    // ENU-MAP
+    gnss_sensor_ptr->getEnuMapRollStatePtr()->setState(Eigen::Vector1s::Zero());
+    gnss_sensor_ptr->getEnuMapPitchStatePtr()->setState(Eigen::Vector1s::Zero());
+    gnss_sensor_ptr->getEnuMapYawStatePtr()->setState(o_enu_map);
+    gnss_sensor_ptr->getEnuMapTranslationStatePtr()->setState(t_enu_map);
+    // Antena
+    gnss_sensor_ptr->getPPtr()->setState(t_base_antena);
+    // Frame
+    frame_ptr->getPPtr()->setState(t_map_base.head(2));
+    frame_ptr->getOPtr()->setState(o_map_base);
+}
+
+void fixAllStates(SensorGnssPtr gnss_sensor_ptr, FrameBasePtr frame_ptr)
+{
+    // ENU-MAP
+    gnss_sensor_ptr->getEnuMapRollStatePtr()->fix();
+    gnss_sensor_ptr->getEnuMapPitchStatePtr()->fix();
+    gnss_sensor_ptr->getEnuMapYawStatePtr()->fix();
+    gnss_sensor_ptr->getEnuMapTranslationStatePtr()->fix();
+    // Antena
+    gnss_sensor_ptr->getPPtr()->fix();
+    // Frame
+    frame_ptr->getPPtr()->fix();
+    frame_ptr->getOPtr()->fix();
+ }
+
+void computeParamSizes(const CeresManagerPtr& ceres_mgr_ptr, int& num_params_reduced, int& num_param_blocks_reduced )
+{
+    num_param_blocks_reduced = 0;
+    num_params_reduced = 0;
+
+    std::vector<Scalar*> param_blocks;
+    ceres_mgr_ptr->getCeresProblemPtr()->GetParameterBlocks(&param_blocks);
+
+    for (auto pb : param_blocks)
+    {
+        std::vector<ceres::ResidualBlockId> residual_blocks;
+        ceres_mgr_ptr->getCeresProblemPtr()->GetResidualBlocksForParameterBlock(pb,&residual_blocks);
+
+        if (!ceres_mgr_ptr->getCeresProblemPtr()->IsParameterBlockConstant(pb) && !residual_blocks.empty())
+        {
+            num_param_blocks_reduced ++;
+            num_params_reduced += ceres_mgr_ptr->getCeresProblemPtr()->ParameterBlockLocalSize(pb);
+        }
+    }
+}
+
+// groundtruth transformations
+Vector1s o_enu_map = (Vector1s() << 2.6).finished();
+Vector3s t_enu_map = (Vector3s() << 12, -34, 4).finished();
+Vector3s t_map_base = (Vector3s() << 32, -34, 0).finished(); // z=0
+Vector1s o_map_base = (Vector1s() << -0.4).finished();
+Vector3s t_base_antena = (Vector3s() << 3,-2,8).finished();// Antena extrinsics
+Vector3s t_ecef_enu = (Vector3s() << 100,30,50).finished();
+Matrix3s R_ecef_enu = (AngleAxis<Scalar>(1.3, Vector3s::UnitX()) *
+                       AngleAxis<Scalar>(-2.2, Vector3s::UnitY()) *
+                       AngleAxis<Scalar>(-1.8, Vector3s::UnitZ())).toRotationMatrix();
+Matrix3s R_enu_map  = AngleAxis<Scalar>(o_enu_map(0),  Vector3s::UnitZ()).toRotationMatrix();
+Matrix3s R_map_base = AngleAxis<Scalar>(o_map_base(0), Vector3s::UnitZ()).toRotationMatrix();
+Vector3s t_ecef_antena = R_ecef_enu * (R_enu_map * (R_map_base * t_base_antena + t_map_base) + t_enu_map ) + t_ecef_enu;
+
+// WOLF
+ProblemPtr problem_ptr = Problem::create("PO 2D");
+CeresManagerPtr ceres_mgr_ptr = std::make_shared<CeresManager>(problem_ptr);
+SensorGnssPtr gnss_sensor_ptr = std::static_pointer_cast<SensorGnss>(problem_ptr->installSensor("GNSS", "gnss", t_base_antena, std::make_shared<IntrinsicsBase>()));
+FrameBasePtr frame_ptr;
+
+////////////////////////////////////////////////////////
+
+TEST(ConstraintGnssFix2DTest, configure_tree)
+{
+    ceres_mgr_ptr->getSolverOptions().max_num_iterations = 100;
+
+    // Configure sensor and processor
+    gnss_sensor_ptr->getEnuMapTranslationStatePtr()->setState(t_enu_map);
+    gnss_sensor_ptr->getEnuMapYawStatePtr()->setState(o_enu_map);
+    gnss_sensor_ptr->getEnuMapRollStatePtr()->fix();
+    gnss_sensor_ptr->getEnuMapPitchStatePtr()->fix();
+    gnss_sensor_ptr->setEnuEcef(R_ecef_enu.transpose(), R_ecef_enu.transpose()*(-t_ecef_enu));
+
+    ProcessorParamsGnssFixPtr gnss_params_ptr = std::make_shared<ProcessorParamsGnssFix>();
+    gnss_params_ptr->time_tolerance = 1.0;
+    gnss_params_ptr->voting_active = true;
+    problem_ptr->installProcessor("GNSS FIX", "gnss fix", gnss_sensor_ptr, gnss_params_ptr);
+
+    // Emplace a frame (FIXED)
+    Vector3s frame_pose = (Vector3s() << t_map_base(0), t_map_base(1), o_map_base(0)).finished();
+    frame_ptr = problem_ptr->emplaceFrame(KEY_FRAME, frame_pose, TimeStamp(0));
+    problem_ptr->keyFrameCallback(frame_ptr, nullptr, 1.0);
+
+    // Create & process GNSS Fix capture
+    CaptureGnssFixPtr cap_gnss_ptr = std::make_shared<CaptureGnssFix>(TimeStamp(0), gnss_sensor_ptr, t_ecef_antena, 1e-3*Matrix3s::Identity());
+    gnss_sensor_ptr->process(cap_gnss_ptr);
+
+    // Checks
+    ASSERT_TRUE(problem_ptr->check(0));
+    ASSERT_TRUE(frame_ptr->isKey());
+}
+
+/*
+ * Test with one GNSS fix capture.
+ *
+ * Estimating: MAP_BASE position.
+ * Fixed: ENU_MAP, MAP_BASE orientation, BASE_ANTENA.
+ */
+TEST(ConstraintGnssFix2DTest, gnss_1_map_base_position)
+{
+    // --------------------------- Reset states
+    resetStates(gnss_sensor_ptr, frame_ptr, o_enu_map, t_base_antena, t_enu_map, t_map_base, o_map_base);
+
+    // --------------------------- fixing/unfixing states
+    fixAllStates(gnss_sensor_ptr, frame_ptr);
+    frame_ptr->getPPtr()->unfix();
+
+    // --------------------------- distort: map base position
+    Vector3s frm_dist = frame_ptr->getState();
+    frm_dist(0) += 0.18;
+    frm_dist(1) += -0.58;
+    frame_ptr->setState(frm_dist);
+
+    // --------------------------- update solver
+    ceres_mgr_ptr->update();
+
+    // --------------------------- check problem parameters
+    int num_params_reduced, num_param_blocks_reduced;
+    computeParamSizes(ceres_mgr_ptr, num_params_reduced, num_param_blocks_reduced);
+
+    ASSERT_EQ(num_param_blocks_reduced, 1);
+    ASSERT_EQ(num_params_reduced, 2);
+
+    // --------------------------- check residuals
+//    int num_residual_blocks_reduced(0);
+//    int num_residual_reduced(0);
+//    ceres_mgr_ptr->getCeresProblem().GetResidualBlocks(&residual_blocks);
+//    for (auto rb : residual_blocks)
+//        if (!ceres_mgr_ptr->getCeresProblem().IsParameterBlockConstant(rb) && ceres_mgr_ptr->getCeresProblem().GetResidualBlocksForParameterBlock(pg))
+//        {
+//            num_param_blocks_reduced ++;
+//            num_params_reduced += ceres_mgr_ptr->getCeresProblem().ParameterBlockLocalSize(rb);
+//        }
+//
+//    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residual_blocks_reduced, 1);
+//    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residuals_reduced, 3);
+
+    // --------------------------- solve
+    std::string report = ceres_mgr_ptr->solve(SolverManager::ReportVerbosity::FULL);
+
+    std::cout << report << std::endl;
+
+    // --------------------------- check summary parameters & residuals
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameter_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameters_reduced, 2);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residual_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residuals_reduced, 3);
+
+    // --------------------------- check solver solution
+    ASSERT_MATRIX_APPROX(frame_ptr->getState().head(2), t_map_base.head(2), 1e-6);
+}
+
+/*
+ * Test with one GNSS fix capture.
+ *
+ * Estimating: MAP_BASE orientation.
+ * Fixed: ENU_MAP, MAP_BASE position, BASE_ANTENA.
+ */
+TEST(ConstraintGnssFix2DTest, gnss_1_map_base_orientation)
+{
+    // --------------------------- Reset states
+    resetStates(gnss_sensor_ptr, frame_ptr, o_enu_map, t_base_antena, t_enu_map, t_map_base, o_map_base);
+
+    // --------------------------- fixing/unfixing states
+    fixAllStates(gnss_sensor_ptr, frame_ptr);
+    frame_ptr->getOPtr()->unfix();
+
+    // --------------------------- distort: map base orientation
+    Vector1s frm_dist = frame_ptr->getOPtr()->getState();
+    frm_dist(0) += 0.18;
+    frame_ptr->getOPtr()->setState(frm_dist);
+
+    // --------------------------- update solver
+    ceres_mgr_ptr->update();
+
+    // --------------------------- check problem parameters
+    int num_params_reduced, num_param_blocks_reduced;
+    computeParamSizes(ceres_mgr_ptr, num_params_reduced, num_param_blocks_reduced);
+
+    ASSERT_EQ(num_param_blocks_reduced, 1);
+    ASSERT_EQ(num_params_reduced, 1);
+
+    // --------------------------- solve
+    std::string report = ceres_mgr_ptr->solve(SolverManager::ReportVerbosity::QUIET);
+
+    // --------------------------- check summary parameters & residuals
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameter_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameters_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residual_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residuals_reduced, 3);
+
+    // --------------------------- check solver solution
+    ASSERT_MATRIX_APPROX(frame_ptr->getOPtr()->getState(), o_map_base, 1e-6);
+}
+
+/*
+ * Test with one GNSS fix capture.
+ *
+ * Estimating: ENU_MAP yaw.
+ * Fixed: ENU_MAP position, MAP_BASE and BASE_ANTENA.
+ */
+TEST(ConstraintGnssFix2DTest, gnss_1_enu_map_yaw)
+{
+    // --------------------------- Reset states
+    resetStates(gnss_sensor_ptr, frame_ptr, o_enu_map, t_base_antena, t_enu_map, t_map_base, o_map_base);
+
+    // --------------------------- fixing/unfixing states
+    fixAllStates(gnss_sensor_ptr, frame_ptr);
+    gnss_sensor_ptr->getEnuMapYawStatePtr()->unfix();
+
+    // --------------------------- distort: yaw enu_map
+    Vector1s o_enu_map_dist = gnss_sensor_ptr->getEnuMapYawStatePtr()->getState();
+    o_enu_map_dist(0) += 0.18;
+    gnss_sensor_ptr->getEnuMapYawStatePtr()->setState(o_enu_map_dist);
+
+    // --------------------------- update solver
+    ceres_mgr_ptr->update();
+
+    // --------------------------- check problem parameters
+    int num_params_reduced, num_param_blocks_reduced;
+    computeParamSizes(ceres_mgr_ptr, num_params_reduced, num_param_blocks_reduced);
+
+    ASSERT_EQ(num_param_blocks_reduced, 1);
+    ASSERT_EQ(num_params_reduced, 1);
+
+    // --------------------------- solve
+    std::string report = ceres_mgr_ptr->solve(SolverManager::ReportVerbosity::QUIET);
+
+    // --------------------------- check summary parameters & residuals
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameter_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameters_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residual_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residuals_reduced, 3);
+
+    // --------------------------- check solver solution
+    ASSERT_MATRIX_APPROX(gnss_sensor_ptr->getEnuMapYawStatePtr()->getState(), o_enu_map, 1e-6);
+}
+
+/*
+ * Test with one GNSS fix capture.
+ *
+ * Estimating: ENU_MAP position.
+ * Fixed: ENU_MAP yaw, MAP_BASE and BASE_ANTENA.
+ */
+TEST(ConstraintGnssFix2DTest, gnss_1_enu_map_position)
+{
+    // --------------------------- Reset states
+    resetStates(gnss_sensor_ptr, frame_ptr, o_enu_map, t_base_antena, t_enu_map, t_map_base, o_map_base);
+
+    // --------------------------- fixing/unfixing states
+    fixAllStates(gnss_sensor_ptr, frame_ptr);
+    gnss_sensor_ptr->getEnuMapTranslationStatePtr()->unfix();// enu-map yaw translation
+
+    // --------------------------- distort: position enu_map
+    Vector3s t_enu_map_dist = gnss_sensor_ptr->getEnuMapTranslationStatePtr()->getState();
+    t_enu_map_dist(0) += 0.86;
+    t_enu_map_dist(1) += -0.34;
+    gnss_sensor_ptr->getEnuMapTranslationStatePtr()->setState(t_enu_map_dist);
+
+    // --------------------------- update solver
+    ceres_mgr_ptr->update();
+
+    // --------------------------- check problem parameters
+    int num_params_reduced, num_param_blocks_reduced;
+    computeParamSizes(ceres_mgr_ptr, num_params_reduced, num_param_blocks_reduced);
+
+    ASSERT_EQ(num_param_blocks_reduced, 1);
+    ASSERT_EQ(num_params_reduced, 3);
+
+    // --------------------------- solve
+    std::string report = ceres_mgr_ptr->solve(SolverManager::ReportVerbosity::QUIET);
+
+    // --------------------------- check summary parameters & residuals
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameter_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameters_reduced, 3);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residual_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residuals_reduced, 3);
+
+    // --------------------------- check solver solution
+    ASSERT_MATRIX_APPROX(gnss_sensor_ptr->getEnuMapTranslationStatePtr()->getState().head(2), t_enu_map.head(2), 1e-6);
+}
+
+/*
+ * Test with one GNSS fix capture.
+ *
+ * Estimating: BASE_ANTENA (2 first components that are observable).
+ * Fixed: ENU_MAP, MAP_BASE.
+ */
+TEST(ConstraintGnssFix2DTest, gnss_1_base_antena)
+{
+    // --------------------------- Reset states
+    resetStates(gnss_sensor_ptr, frame_ptr, o_enu_map, t_base_antena, t_enu_map, t_map_base, o_map_base);
+
+    // --------------------------- fixing/unfixing states
+    fixAllStates(gnss_sensor_ptr, frame_ptr);
+    gnss_sensor_ptr->getPPtr()->unfix();
+
+    // --------------------------- distort: base_antena
+    Vector3s base_antena_dist = gnss_sensor_ptr->getPPtr()->getState();
+    base_antena_dist(0) += 1.68;
+    base_antena_dist(0) += -0.48;
+    gnss_sensor_ptr->getPPtr()->setState(base_antena_dist);
+
+    // --------------------------- update solver
+    ceres_mgr_ptr->update();
+
+    // --------------------------- check problem parameters
+    int num_params_reduced, num_param_blocks_reduced;
+    computeParamSizes(ceres_mgr_ptr, num_params_reduced, num_param_blocks_reduced);
+
+    ASSERT_EQ(num_param_blocks_reduced, 1);
+    ASSERT_EQ(num_params_reduced, 3);
+
+    // --------------------------- solve
+    std::string report = ceres_mgr_ptr->solve(SolverManager::ReportVerbosity::QUIET);
+
+    // --------------------------- check summary parameters & residuals
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameter_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_parameters_reduced, 3);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residual_blocks_reduced, 1);
+    ASSERT_EQ(ceres_mgr_ptr->getSummary().num_residuals_reduced, 3);
+
+    // --------------------------- check solver solution
+    ASSERT_MATRIX_APPROX(gnss_sensor_ptr->getPPtr()->getState().head(2), t_base_antena.head(2), 1e-6);
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+