Edit:
Вы можете решить нелинейную изменяющуюся во времени систему легко с odeint
. Следующий пример нелинейной нестационарной системы берется из Applied Nonlinear Control by Slotine
Обратите внимание, что мы можем вставить 6sin(t)
внутри ode
безопасно, так как мы ничего не делаем на каждом шаге по времени. Если ваша система имеет контроллер, который зависит от временного шага, такого как ПИД-регулятор, для которого требуется дельта-время для вычисления производных, тогда в этом случае не помещайте его внутри ode
, так как ode()
вызывается несколько раз решателем ode. Это мой код для решения системы.
#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;
}
Результат (то есть результат, представленный в вышеупомянутой книге).
Привет, есть одна проблема: во время одного шага решатель будет вызывать функцию ода несколько раз с разными значениями времени. Например, RK4 может использовать его со временем t, t + dt/2, t + dt/2, t + dt за один шаг. Это можно легко решить, изменив класс на '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
@headmyshoulder, вы определенно правы. Я буду обновлять ответ, чтобы отразить эту проблему, и, конечно, нет необходимости в 'GetTImeParameter()'. – CroCo
@ macropod, см. Обновление. – CroCo