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:
Summarizing, what I want to do is:
- Obtaining an array with the Force wrt time (easy)
- Since a is the derivative of v, and we now have a variable F depending on time, I want to solve the differential equation:
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:
And, here, for ‘coef’ = 1.5:
I am not understanding the origin of the issue. Any help will be welcome!
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.
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!
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:
Summarizing, what I want to do is:
- Obtaining an array with the Force wrt time (easy)
- Since a is the derivative of v, and we now have a variable F depending on time, I want to solve the differential equation:
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:
And, here, for ‘coef’ = 1.5:
I am not understanding the origin of the issue. Any help will be welcome!
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.
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!