Boost OdeInt积分例程中类属性无法正确保留值的问题
问题描述
我正在使用boost::numeric::odeint构建自定义积分器,除计算状态的离散导数外,还在每次进入operator()的积分步骤中计算输出方程(已知此方式效率不高,仅用于理解库的工作机制)。调试发现,operator()方法内的y和test变量计算正常,但返回主循环后,sys对象的y和test变量变为未初始化状态。
TestSystem.h
#pragma once #include <Eigen/Dense> #include <iostream> using namespace std; using namespace Eigen; const int n = 2; // 状态量维度 const int q = 1; // 输出量维度 const int m = 1; // 输入量维度 typedef Vector<double, n> state_type; typedef Vector<double, m> input_type; typedef Vector<double, q> output_type; typedef Matrix<double, n, n> state_matrix_type; typedef Matrix<double, n, m> input_matrix_type; typedef Matrix<double, q, n> output_matrix_type; typedef Matrix<double, q, m> feedthrough_matrix_type; class TestSystem { public: state_matrix_type A{ { -4.0, -3.0}, { 1.0, 0.0} }; input_matrix_type B{ 1.0, 0.0 }; output_matrix_type C{ 1.0, 1.0 }; feedthrough_matrix_type D{ 0.0 }; double test; input_type u; output_type y; void operator() (const state_type& x, state_type& x_dot, const double t); };
TestSystem.cpp
#include "TestSystem.h" void TestSystem::operator()(const state_type& x, state_type& x_dot, const double t) { x_dot = A * x + B * u; this->y = C * x + D * u; this->test = (C * x + D * u)(0); cout << "积分步骤内计算的输出值: " << this->test << endl; }
main.cpp
#include <iostream> #include <Eigen/Dense> #include "TestSystem.h" using namespace Eigen; using namespace std; using namespace cnpy; const double PI = 3.14159265359; const int N = 5000; VectorXd u(N); #include <boost/numeric/odeint/stepper/runge_kutta4.hpp> #include <boost/numeric/odeint/integrate/integrate_n_steps.hpp> using namespace boost::numeric::odeint; int main() { VectorXd t(N); t = VectorXd::LinSpaced(N, 0.0, 1.0); TestSystem sys; u = (2 * PI * 200 * t).array().cos() + (2 * PI * 20 * t).array().sin(); state_type x = state_type::Zero(); // 仅运行一步作为示例 for (size_t i = 0; i < 1; i++) { input_type _u{ u(i) }; // _u << u(i); sys.u = _u; runge_kutta4<state_type> rk; rk.do_step(sys, x, t(i), t(1)); cout << "主循环中sys对象的test变量值: " << sys.test << endl; } }
运行结果
积分步骤内计算的输出值: 0 积分步骤内计算的输出值: 0.00010002 积分步骤内计算的输出值: 9.999e-05 积分步骤内计算的输出值: 0.00019998 主循环中sys对象的test变量值: -9.25596e+61
问题原因与解决方法
原因
runge_kutta4的do_step方法会复制传入的系统对象(即sys)进行内部计算,你在operator()中修改的是副本的y和test成员,而非原对象的。当do_step执行完毕后,副本被销毁,原对象的y和test从未被正确赋值,因此呈现未初始化的垃圾值。
解决方法
使用boost::ref包装系统对象,让do_step直接操作原对象而非副本:
rk.do_step(boost::ref(sys), x, t(i), t(1));
修改后,operator()中对y和test的修改会直接作用于原sys对象,主循环就能获取到正确的计算结果。
内容的提问来源于stack exchange,提问作者Buzz
相关产品推荐
相关产品推荐

