Unaccurate solve_ivp solution to non-homogeneous ODE (Python)

Question:

Today, I started working for the first time with solve_ivp. My problem is the following:

I have data from an accelerometer and speedometer ( variables a and v in the code), which correspond to the motion data of a body under a fluid. The governing equation of motion is:

eq1

Summarizing, what I want to do is:

  1. Obtaining an array with the Force wrt time (easy)
  2. Since a is the derivative of v, and we now have a variable F depending on time, I want to solve the differential equation:

eq2

and compare the recovered velocity with the original measured one.

My attempt:

I am using solve_ivp for this, and this is my code (I assumed that m=1, so I omited it in the calculations):

def obtainF(self, v, a):
    return(a + self.coef * v**2)


def eqMot(self, t, y, F, coef):
    return(F[t] - coef*y*y)

def diffSolver(self, F): 

    t = linspace(0,len(F)-1,len(F))

    y0 = [0.0]
    p = [F, self.coef]

    sol = solve_ivp(self.eqMot, [0, len(F)-1], y0, args = p, t_eval=t)

    return(sol.y[0])

(the code is pretty much self-explainatory). Code updated afterDavidJ answer (the issue remains)

The original acceleration and velocity are pretty much sinusoids with a small low-frequency offset. They are even low-pass filtered in advance in order to avoid any conflict with the solver.

The issue:

The original and computed velocities do not mach. Not only that, but the missmatch seems to decrease when increasing ‘coef’.

Obtained plot for ‘coef’ = 0.2:

plot1

And, here, for ‘coef’ = 1.5:

plot2

I am not understanding the origin of the issue. Any help will be welcome!

Asked By: user3141592

||

Answers:

The system presented is first-order. I believe you are trying to solve the following.

def obtainF(self, v, a):
    return(a + self.coef * v * v)


def eqMot(self, t, v, F, coef):
    # indexing `F` with a float `t` can lead to problems. 
    # Use interpolation of `F` to ensure this evaluates correctly.
    return(F(t) - coef * v * v)

def diffSolver(self, F): 

    t = linspace(0.0,len(F)-1.0,len(F))

    y0 = [0.0]
    # According to the API doc `args` should be a tuple
    p = (F, self.coef)

    sol = solve_ivp(self.eqMot, [0.0, len(F)-1.0], y0, args = p, t_eval=t)

    v_new = sol.y

    return v_new

It appears you’re mixing object-oriented and functional programming styles too. Consider which one makes more sense and implement consistently.

Answered By: DavidJ

So I managed to solve the problem. As @LutzLehmann suggested in a comment, since I was taking the velocity measurements from one sensor and the acceleration data from a different one, even though at a first glance the later seemed the derivative of the former, in a sample-by-sample it turned out that there were significant differences between de (manually computed) derivative of speed and accel.

I solved it by mixing both sources of data with a complementary filter and working with the resulting velocity vector, differentiating it afterwards.

Thanks for the help!

Answered By: user3141592