diff --git a/plot_IMU_mocap_result.py b/plot_IMU_mocap_result.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f6b4114fb1d019146cbf2b6b9a6070425cf8314
--- /dev/null
+++ b/plot_IMU_mocap_result.py
@@ -0,0 +1,381 @@
+
+import numpy as np
+from matplotlib import pyplot as plt
+import pinocchio as pin
+import tsid as tsid
+
+
+def linearly_interpolate_nans(y):
+    # Fit a linear regression to the non-nan y values
+
+    # Create X matrix for linreg with an intercept and an index
+    X = np.vstack((np.ones(len(y)), np.arange(len(y))))
+
+    # Get the non-NaN values of X and y
+    X_fit = X[:, ~np.isnan(y)]
+    y_fit = y[~np.isnan(y)].reshape(-1, 1)
+
+    # Estimate the coefficients of the linear regression
+    beta = np.linalg.lstsq(X_fit.T, y_fit)[0]
+
+    # Fill in all the nan values using the predicted coefficients
+    y.flat[np.isnan(y)] = np.dot(X[:, np.isnan(y)].T, beta)
+    return y
+
+
+def cross3(left, right):
+    """Numpy is inefficient for this
+
+    Args:
+        left (3x0 array): left term of the cross product
+        right (3x0 array): right term of the cross product
+    """
+    return np.array([[left[1] * right[2] - left[2] * right[1]],
+                     [left[2] * right[0] - left[0] * right[2]],
+                     [left[0] * right[1] - left[1] * right[0]]])
+
+
+def BaseVelocityFromKinAndIMU(contactFrameId, model, data, IMU_ang_vel):
+    """Estimate the velocity of the base with forward kinematics using a contact point
+    that is supposed immobile in world frame
+
+    Args:
+        contactFrameId (int): ID of the contact point frame (foot frame)
+    """
+
+    frameVelocity = pin.getFrameVelocity(
+        model, data, contactFrameId, pin.ReferenceFrame.LOCAL)
+    framePlacement = pin.updateFramePlacement(
+        model, data, contactFrameId)
+
+    # Angular velocity of the base wrt the world in the base frame (Gyroscope)
+    _1w01 = IMU_ang_vel.reshape((3, 1))
+    # Linear velocity of the foot wrt the base in the base frame
+    _Fv1F = frameVelocity.linear
+    # Level arm between the base and the foot
+    _1F = framePlacement.translation
+    # Orientation of the foot wrt the base
+    _1RF = framePlacement.rotation
+    # Linear velocity of the base from wrt world in the base frame
+    _1v01 = cross3(_1F.ravel(), _1w01.ravel()) - \
+        (_1RF @ _Fv1F.reshape((3, 1)))
+
+    return _1v01
+
+#########
+# START #
+#########
+
+
+# Load data file
+data = np.load("../../Tests_Python/data.npz")
+
+# Store content of data in variables
+
+# From Mocap
+mocapPosition = data['mocapPosition']  # Position
+mocapOrientationQuat = data['mocapOrientationQuat']  # Orientation as quat
+mocapOrientationMat9 = data['mocapOrientationMat9']  # as 3 by 3 matrix
+mocapVelocity = data['mocapVelocity']  # Linear velocity
+mocapAngularVelocity = data['mocapAngularVelocity']  # Angular velocity
+
+# Fill NaN mocap values with linear interpolation
+for i in range(3):
+    mocapPosition[:, i] = linearly_interpolate_nans(mocapPosition[:, i])
+    mocapVelocity[:, i] = linearly_interpolate_nans(mocapVelocity[:, i])
+    mocapAngularVelocity[:, i] = linearly_interpolate_nans(
+        mocapAngularVelocity[:, i])
+
+# From IMU
+baseOrientation = data['baseOrientation']  # Orientation as quat
+baseLinearAcceleration = data['baseLinearAcceleration']  # Linear acceleration
+baseAngularVelocity = data['baseAngularVelocity']  # Angular Vel
+
+# IMU is upside down so we have to reorder the data
+"""tmp = baseOrientation[:, 0].copy()
+baseOrientation[:, 0] = baseOrientation[:, 1].copy()
+baseOrientation[:, 1] = tmp
+baseOrientation[:, 2] = - baseOrientation[:, 2].copy()
+tmp = baseLinearAcceleration[:, 0].copy()
+baseLinearAcceleration[:, 0] = baseLinearAcceleration[:, 1].copy()
+baseLinearAcceleration[:, 1] = tmp
+baseLinearAcceleration[:, 2] = - baseLinearAcceleration[:, 2].copy()
+tmp = baseAngularVelocity[:, 0].copy()
+baseAngularVelocity[:, 0] = baseAngularVelocity[:, 1].copy()
+baseAngularVelocity[:, 1] = tmp
+baseAngularVelocity[:, 2] = - baseAngularVelocity[:, 2].copy()"""
+
+# From actuators
+torquesFromCurrentMeasurment = data['torquesFromCurrentMeasurment']  # Torques
+q_mes = data['q_mes']  # Angular positions
+v_mes = data['v_mes']  # Angular velocities
+
+# Creating time vector
+Nlist = np.where(mocapPosition[:, 0] == 0.0)[0]
+if len(Nlist) > 0:
+    N = Nlist[0]
+else:
+    N = mocapPosition.shape[0]
+Tend = N * 0.001
+t = np.linspace(0, Tend, N+1, endpoint=True)
+t = t[:-1]
+
+# Parameters
+dt = 0.001
+lwdth = 2
+
+###############
+# ORIENTATION #
+###############
+
+mocapRPY = np.zeros((N, 3))
+imuRPY = np.zeros((N, 3))
+for i in range(N):
+    mocapRPY[i, :] = pin.rpy.matrixToRpy(mocapOrientationMat9[i, :, :])
+    imuRPY[i, :] = pin.rpy.matrixToRpy(pin.Quaternion(
+        baseOrientation[i:(i+1), :].transpose()).toRotationMatrix())
+
+fig = plt.figure()
+# Roll orientation
+ax0 = plt.subplot(2, 1, 1)
+plt.plot(t, mocapRPY[:N, 0], "darkorange", linewidth=lwdth)
+plt.plot(t, imuRPY[:N, 0], "royalblue", linewidth=lwdth)
+plt.ylabel("Roll")
+plt.legend(["Mocap", "IMU"], prop={'size': 8})
+# Pitch orientation
+ax1 = plt.subplot(2, 1, 2, sharex=ax0)
+plt.plot(t, mocapRPY[:N, 1], "darkorange", linewidth=lwdth)
+plt.plot(t, imuRPY[:N, 1], "royalblue", linewidth=lwdth)
+plt.ylabel("Pitch")
+plt.xlabel("Time [s]")
+
+###################
+# LINEAR VELOCITY #
+###################
+mocapBaseLinearVelocity = np.zeros((N, 3))
+imuBaseLinearVelocity = np.zeros((N, 3))
+for i in range(N):
+    mocapBaseLinearVelocity[i, :] = ((mocapOrientationMat9[i, :, :]).transpose() @
+                                     (mocapVelocity[i:(i+1), :]).transpose()).ravel()
+    if i == 0:
+        imuBaseLinearVelocity[i, :] = mocapBaseLinearVelocity[0, :]
+    else:
+        imuBaseLinearVelocity[i, :] = imuBaseLinearVelocity[i -
+                                                            1, :] + dt * baseLinearAcceleration[i-1, :]
+
+fig = plt.figure()
+# X linear velocity
+ax0 = plt.subplot(3, 1, 1)
+plt.plot(t, mocapBaseLinearVelocity[:N, 0], "darkorange", linewidth=lwdth)
+plt.plot(t, imuBaseLinearVelocity[:N, 0], "royalblue", linewidth=lwdth)
+plt.ylabel("$\dot x$ [m/s]")
+plt.legend(["Mocap", "IMU"], prop={'size': 8})
+# Y linear velocity
+ax1 = plt.subplot(3, 1, 2, sharex=ax0)
+plt.plot(t, mocapBaseLinearVelocity[:N, 1], "darkorange", linewidth=lwdth)
+plt.plot(t, imuBaseLinearVelocity[:N, 1], "royalblue", linewidth=lwdth)
+plt.ylabel("$\dot y$ [m/s]")
+# Z linear velocity
+ax1 = plt.subplot(3, 1, 3, sharex=ax0)
+plt.plot(t, mocapBaseLinearVelocity[:N, 2], "darkorange", linewidth=lwdth)
+plt.plot(t, imuBaseLinearVelocity[:N, 2], "royalblue", linewidth=lwdth)
+plt.ylabel("$\dot z$ [m/s]")
+plt.xlabel("Time [s]")
+
+######################
+# ANGULAR VELOCITIES #
+######################
+mocapBaseAngularVelocity = np.zeros(mocapAngularVelocity.shape)
+for i in range(N):
+    mocapBaseAngularVelocity[i, :] = ((mocapOrientationMat9[i, :, :]).transpose() @
+                                      (mocapAngularVelocity[i:(i+1), :]).transpose()).ravel()
+fig = plt.figure()
+# Angular velocity X subplot
+ax0 = plt.subplot(3, 1, 1)
+plt.plot(t, mocapBaseAngularVelocity[:N, 0], "darkorange", linewidth=lwdth)
+plt.plot(t, baseAngularVelocity[:N, 0], "royalblue", linewidth=lwdth)
+plt.ylabel("$\dot \phi$ [rad/s]")
+plt.legend(["Mocap", "IMU"], prop={'size': 8})
+# Angular velocity Y subplot
+ax1 = plt.subplot(3, 1, 2, sharex=ax0)
+plt.plot(t, mocapBaseAngularVelocity[:N, 1], "darkorange", linewidth=lwdth)
+plt.plot(t, baseAngularVelocity[:N, 1], "royalblue", linewidth=lwdth)
+plt.ylabel("$\dot \\theta$ [rad/s]")
+# Angular velocity Z subplot
+ax2 = plt.subplot(3, 1, 3, sharex=ax0)
+plt.plot(t, mocapBaseAngularVelocity[:N, 2], "darkorange", linewidth=lwdth)
+plt.plot(t, baseAngularVelocity[:N, 2], "royalblue", linewidth=lwdth)
+plt.ylabel("$\dot \psi$ [rad/s]")
+plt.xlabel("Time [s]")
+
+#######################
+# LINEAR ACCELERATION #
+#######################
+
+fig = plt.figure()
+# X linear acc
+ax0 = plt.subplot(3, 1, 1)
+plt.plot(t, baseLinearAcceleration[:N, 0], "royalblue", linewidth=lwdth)
+plt.ylabel("$\ddot x$ [m/s^2]")
+plt.legend(["IMU"], prop={'size': 8})
+# Y linear acc
+ax1 = plt.subplot(3, 1, 2, sharex=ax0)
+plt.plot(t, baseLinearAcceleration[:N, 1], "royalblue", linewidth=lwdth)
+plt.ylabel("$\ddot y$ [m/s^2]")
+# Z linear acc
+ax1 = plt.subplot(3, 1, 3, sharex=ax0)
+plt.plot(t, baseLinearAcceleration[:N, 2], "royalblue", linewidth=lwdth)
+plt.ylabel("$\ddot z$ [m/s^2]")
+plt.xlabel("Time [s]")
+
+#############
+# ACTUATORS #
+#############
+
+index = [1, 5, 2, 6, 3, 7, 4, 8]
+plt.figure()
+for i in range(8):
+    if i == 0:
+        ax0 = plt.subplot(2, 4, index[i])
+    else:
+        plt.subplot(2, 4, index[i], sharex=ax0)
+    plt.plot(
+        t, torquesFromCurrentMeasurment[:N, i], "forestgreen", linewidth=lwdth)
+
+    if (i % 2 == 1):
+        plt.xlabel("Time [s]")
+    if i <= 1:
+        plt.ylabel("Torques [N.m]")
+
+contact_state = np.zeros((N, 4))
+margin = 25
+treshold = 0.4
+for i in range(4):
+    state = 0
+    front_up = 0
+    front_down = 0
+    for j in range(N):
+        if (state == 0) and (np.abs(torquesFromCurrentMeasurment[j, 2*i+1]) >= treshold):
+            state = 1
+            front_up = j
+        if (state == 1) and (np.abs(torquesFromCurrentMeasurment[j, 2*i+1]) < treshold):
+            state = 0
+            front_down = j
+            l = np.min((front_up+margin, N))
+            u = np.max((front_down-margin, 0))
+            contact_state[l:u, i] = 1
+
+plt.figure()
+for i in range(4):
+    if i == 0:
+        ax0 = plt.subplot(1, 4, i+1)
+    else:
+        plt.subplot(1, 4, i+1, sharex=ax0)
+    plt.plot(t, torquesFromCurrentMeasurment[:N, 2*i+1])
+    plt.plot(t, contact_state[:N, i])
+    plt.legend(["Torque", "Estimated contact state"], prop={'size': 8})
+
+"""fig = plt.figure()
+# Angular velocity X subplot
+ax0 = plt.subplot(3, 1, 1)
+plt.plot(t, torquesFromCurrentMeasurment[:N,
+                                         0], "forestgreen", linewidth=lwdth)
+plt.ylabel("Torques [N.m]")
+# Angular velocity Y subplot
+ax1 = plt.subplot(3, 1, 2, sharex=ax0)
+plt.plot(t, q_mes[:N, 0], "forestgreen", linewidth=lwdth)
+plt.ylabel("Angular position [rad]")
+# Angular velocity Z subplot
+ax2 = plt.subplot(3, 1, 3, sharex=ax0)
+plt.plot(t, v_mes[:N, 2], "forestgreen", linewidth=lwdth)
+plt.ylabel("Angular velocity [rad/s]")
+plt.xlabel("Time [s]")"""
+
+
+# Set the paths where the urdf and srdf file of the robot are registered
+modelPath = "/opt/openrobots/share/example-robot-data/robots"
+urdf = modelPath + "/solo_description/robots/solo.urdf"
+srdf = modelPath + "/solo_description/srdf/solo.srdf"
+vector = pin.StdVec_StdString()
+vector.extend(item for item in modelPath)
+
+# Create the robot wrapper from the urdf model (which has no free flyer) and add a free flyer
+robot = tsid.RobotWrapper(
+    urdf, vector, pin.JointModelFreeFlyer(), False)
+model = robot.model()
+
+# Creation of the Invverse Dynamics HQP problem using the robot
+# accelerations (base + joints) and the contact forces
+invdyn = tsid.InverseDynamicsFormulationAccForce(
+    "tsid", robot, False)
+
+# Compute the problem data with a solver based on EiQuadProg
+t0 = 0.0
+q_FK = np.zeros((15, 1))
+q_FK[:7, 0] = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0])
+v_FK = np.zeros((14, 1))
+invdyn.computeProblemData(t0, q_FK, v_FK)
+data = invdyn.data()
+
+indexes = [8, 14, 20, 26]
+alpha = 0.98
+filteredLinearVelocity = np.zeros((N, 3))
+"""for a in range(len(model.frames)):
+    print(a)
+    print(model.frames[a])"""
+FK_lin_vel_log = np.nan * np.zeros((N, 3))
+rms_x = []
+rms_y = []
+rms_z = []
+alphas = [0.97]  # [0.01*i for i in range(100)]
+i_not_nan = np.where(np.logical_not(np.isnan(mocapBaseLinearVelocity[:, 0])))
+i_not_nan = (i_not_nan[0])[(i_not_nan[0] < 9600)]
+for alpha in alphas:
+    filteredLinearVelocity = np.zeros((N, 3))
+    for i in range(N):
+        # Update estimator FK model
+        q_FK[7:, 0] = q_mes[i, :]  # Position of actuators
+        v_FK[6:, 0] = v_mes[i, :]  # Velocity of actuators
+
+        pin.forwardKinematics(model, data, q_FK, v_FK)
+
+        # Get estimated velocity from updated model
+        cpt = 0
+        vel_est = np.zeros((3, ))
+        for j in (np.where(contact_state[i, :] == 1))[0]:
+            vel_estimated_baseframe = BaseVelocityFromKinAndIMU(
+                indexes[j], model, data, baseAngularVelocity[i, :])
+
+            cpt += 1
+            vel_est += vel_estimated_baseframe[:, 0]
+        if cpt > 0:
+            FK_lin_vel = vel_est / cpt  # average of all feet in contact
+
+            filteredLinearVelocity[i, :] = alpha * (filteredLinearVelocity[i-1, :] + baseLinearAcceleration[i, :] * dt) \
+                + (1 - alpha) * FK_lin_vel
+            FK_lin_vel_log[i, :] = FK_lin_vel
+        else:
+            filteredLinearVelocity[i, :] = filteredLinearVelocity[i -
+                                                                  1, :] + baseLinearAcceleration[i, :] * dt
+    rms_x.append(
+        np.sqrt(np.mean(np.square(filteredLinearVelocity[i_not_nan, 0] - mocapBaseLinearVelocity[i_not_nan, 0]))))
+    rms_y.append(
+        np.sqrt(np.mean(np.square(filteredLinearVelocity[i_not_nan, 1] - mocapBaseLinearVelocity[i_not_nan, 1]))))
+    rms_z.append(
+        np.sqrt(np.mean(np.square(filteredLinearVelocity[i_not_nan, 2] - mocapBaseLinearVelocity[i_not_nan, 2]))))
+
+plt.figure()
+plt.plot(alphas, rms_x)
+plt.plot(alphas, rms_y)
+plt.plot(alphas, rms_z)
+plt.legend(["RMS X", "RMS Y", "RMS Z"], prop={'size': 8})
+plt.xlabel("Alpha")
+plt.ylabel("RMS erreur en vitesse")
+
+plt.figure()
+plt.plot(t, filteredLinearVelocity[:N, 0], linewidth=3)
+plt.plot(t, mocapBaseLinearVelocity[:N, 0], linewidth=3)
+plt.plot(t, FK_lin_vel_log[:N, 0], color="rebeccapurple", linestyle="--")
+"""plt.plot(t, baseLinearAcceleration[:N, 0], linestyle="--")"""
+plt.legend(["Filtered", "Mocap", "FK"], prop={'size': 8})
+plt.show()