You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:14:55