tBuLi / symfit

Symbolic Fitting; fitting as it should be.
http://symfit.readthedocs.org
MIT License
233 stars 17 forks source link

How to model ODE with variable independent 'input' variables other than 't'? #235

Open iroychoudhury opened 5 years ago

iroychoudhury commented 5 years ago

I apologize if this is not the best place for this, but I am trying to fit an ODEModel that includes a variable 'input' parameter.

Basically, if I have the following differential equations for a DC motor:

from symfit import Parameter, variables, ODEModel, Fit, D
import numpy as np

i_a, w, t = variables('i_a, w, t')
L = Parameter('L', 0.1)
R = Parameter('R', 0.1)
k = Parameter('k', 0.1)
J = Parameter('J', 0.1)
B = Parameter('B', 0.1)
Vs = Parameter('Vs', data_c_compact['w1_pumpspeed']) 

model_dict = {
    D(i_a, t): (1/L) * (Vs - R * i_a - k * w),
    D(w, t): (1/J) * (k * i_a - B * w)
}
Vs0 = data_c_compact['w1_pumpspeed'][0]
Vsdata = data_c_compact['w1_pumpspeed']

ode_model = ODEModel(model_dict, initial={t: 0, i_a: 0, w: 0})
fit = Fit(ode_model, t=data_c_compact['seconds_total'], i_a=None, w=None)
fit_result = fit.execute()

So Vs is basically an input that keeps changing. However, when I run it, I get the error AttributeError: 'Variable' object has no attribute 'symbol'

I have also tried making 'Vs' a variable, but get another error saying TypeError: got an unexpected keyword argument 'Vs'. The code for that is below:

from symfit import Parameter, variables, ODEModel, Fit, D
import numpy as np

i_a, w, t, Vs = variables('i_a, w, t, Vs')
L = Parameter('L', 0.1)
R = Parameter('R', 0.1)
k = Parameter('k', 0.1)
J = Parameter('J', 0.1)
B = Parameter('B', 0.1)

model_dict = {
    D(i_a, t): (1/L) * (Vs - R * i_a - k * w),
    D(w, t): (1/J) * (k * i_a - B * w)
}

Vs0 = data_c_compact['w1_pumpspeed'][0]
Vsdata = data_c_compact['w1_pumpspeed']

ode_model = ODEModel(model_dict, initial={t: 0, i_a: 0, w: 0, Vs: 0})
fit = Fit(ode_model, t=data_c_compact['seconds_total'], i_a=None, w=None, Vs = Vsdata)
fit_result = fit.execute()

Please help!

tBuLi commented 5 years ago

Hello @iroychoudhury, thanks for your question.

I must admit I'm a bit confused about what you are trying to do here, do you have an easy reference for me perhaps? From reading your code, there are a couple of things I'm curious about:

Let me know the answers to these question, and perhaps then I can help you further :).

iroychoudhury commented 5 years ago

Hello @tBuLi, thank you for kindly taking the time to respond to this. Sorry for the confusing wall of text above. What you understand is correct. I do have a Vs value for every t value.

I am trying to identify the parameters for a DC motor. In the state-space formulation, state variables = {i_a, w}, parameters = {L, R, k, J, B}, input = {Vs}, and output = {f}, where:

The state transition model is:

D(i_a, t): (1/L) * (Vs - R * i_a - k * w),
D(w, t): (1/J) * (k * i_a - B * w)

The observation model is: RPM = 55.3 * w. So for every value of t, I also have a value for RPM and a value for Vs, and I want to match and fit the parameters for L, R, J, and B.

How should I do it using sympy? Thank you again for your help! :) Much appreciated!

tBuLi commented 5 years ago

Thank you for your explanation. So in principle, Fit should be called as

wdata = RPM / 55.3
fit = Fit(ode_model, t=data_c_compact['seconds_total'], i_a=None, w=wdata, Vs=Vsdata)

However, regarding your ODE I'm afraid ODEModel will not work because currently that only supports one independent variable, t, but in your case you have two independent variables, t and Vs.

You could try to solve your ODE analytically using sympy: https://docs.sympy.org/latest/modules/solvers/ode.html Not sure if your system has a closed solution but it is worth a shot.

Otherwise, you will have to play with scipy's ode solvers to see if you can get this to work, and then build a CallableNumericalModel to feed that solution to symfit. Let me know if you do find a solution in anyway, I'm invested in this problem now :P.