1

I am trying to numerically integrate a nonlinear system using boost::odeint. The system has time-varying parameters that are generated externally, and I want to incorporate this into my program. Is this possible with odeint? In Matlab, if you were to do something similar, you would need to interpolate the values as they become available.

Thank you in advance for your help!

macropod
  • 25
  • 3

2 Answers2

0

Yes, this is possible. But you might need to interpolate the values too. You interact with the solver via the system function. It can be functor and it can contain the a link to the data, for example

struct ode
{
    void operator()( const state_type& x , state_type& dxdt , double t ) const
    {
         // get the the parameter from time_varying_parameters
    }
    std::vector<double> time_varying_parameters;
};
headmyshoulder
  • 6,240
  • 2
  • 20
  • 27
0

Edit:

You can solve nonlinear time-varying system easily with odeint. The following example of a nonlinear time-varying system is taken from Applied Nonlinear Control by Slotine

enter image description here

Notice that we can insert 6sin(t) inside ode safely since we are not doing anything at each time step. If your system has a controller that depends on a time step like PID controller that requires delta time to compute derivatives, then in this case, don't put it inside the ode since ode() is called several times by the ode solver. This is my code for solving the system.

#include <iostream>
#include <boost/math/constants/constants.hpp>
#include <boost/numeric/odeint.hpp>
#include <fstream>

std::ofstream data("data.txt");

using namespace boost::numeric::odeint;

typedef std::vector< double > state_type;

class System
{
public:
    System(const double& deltaT);
    void updateODE();
    void updateSystem();
private:
    double t, dt;
    runge_kutta_dopri5 < state_type > stepper;
    state_type y;
    void ode(const state_type &y, state_type &dy, double t);

};

System::System(const double& deltaT) : dt(deltaT), t(0.0), y(2)
{
    /*
       x = y[0]
      dx = y[1] = dy[0]
     ddx        = dy[1] = ode equation
     */

    // initial values
    y[0] = 2.0;  //  x1 
    y[1] = 0.0;  //  x2
}

void System::updateODE()
{
    // store data for plotting  
    data << t << " " << y[0] << std::endl;

    //=========================================================================
    using namespace std::placeholders;
    stepper.do_step(std::bind(&System::ode, this, _1, _2, _3), y, t, dt);
    t += dt;
}

void System::updateSystem()
{
    // you can utitilize this function in case you have a controller and 
    // you need to update the controller at a fixed step size. 

}

void System::ode(const state_type &y, state_type &dy, double t)
{
    //#####################( ODE Equation )################################
    dy[0] = y[1];
    dy[1] = 6.0*sin(t) - 0.1*y[1] - pow(y[0],5);
}

int main(int argc, char **argv)
{
    const double dt(0.001); 
    System sys(dt);

    for (double t(0.0); t <= 50.0; t += dt){
        // update time-varying parameters of the system 
        //sys.updateSystem();
        // solve the ODE one step forward. 
        sys.updateODE();
    }

    return 0;
}

The result is (i.e. same result presented in the aforementioned book).

enter image description here

CroCo
  • 5,531
  • 9
  • 56
  • 88
  • Hi, there is one problem: During one step the solver will call the ode function several times with with different time values. For example, RK4 will can it with the times t, t+dt/2, t+dt/2, t+dt during one step. This can easily be solved by changing your class to `double GetTImeParameter(double t) { return 6 * sin(t) } ode(const state_type &y, state_type &dy, double t) { dy[0] = y[1]; dy[1] = GetTimeParameter(t) - 0.1*y[1] - pow(y[0],5); }` – headmyshoulder Aug 04 '16 at 13:31
  • @headmyshoulder, you're definitely right. I will update the answer to reflect this issue and of course there is no need to `GetTImeParameter()`. – CroCo Aug 05 '16 at 13:59