在Matlab中保存ode45中的导数值

时间:2013-05-14 08:25:54

标签: matlab ode derivative

我用质量弹簧和双摆来模拟一个(有点奇怪的)系统的运动方程,我有一个质量矩阵和函数f(x),并调用ode45求解

M*x' = f(x,t);

我有5个状态变量,q = [QDot,phi,phiDot,r,rDot]&#39 ;; (删除Q因为没有任何依赖它,QDot是最新的。) 现在,为了计算一些力,我还想保存rDotDot的计算值,ode45为每个积分步骤计算,但是ode45没有给出这个。我已经搜索了一下,但我发现的唯一两个解决方案是 a)将其转换为3阶问题,并将phiDotDot和rDotDot添加到状态向量中。我想尽可能地避免这种情况,因为它已经是非线性的,这确实使事情变得更糟,并且耗费了计算时间。

b)增加状态以直接计算函数,如here所述。但是,在示例中,他说要在质量矩阵中添加一行零。这是有道理的,因为否则它将整合衍生物而不仅仅在一点评估它,但另一方面它使质量矩阵单数。似乎不适合我...

这看起来像是一个基本的东西(想要状态向量的导数值),是否有一些我不想的东西? (或者不太明显的东西也可以......)

哦,全局变量不是很大,因为ode45在完善它的步骤时多次调用f()函数,所以全局变量的大小和返回的状态向量q不匹配一点都不。

如果有人需要,请输入以下代码:

%(Initialization of parameters are above this line)
   options = odeset('Mass',@massMatrix);
   [T,q] = ode45(@f, tspan,q0,options);

function dqdt = f(t,q,p)
    % q = [qDot phi phiDot r rDot]';

    dqdt = zeros(size(q));

    dqdt(1) = -R/L*q(1) - kb/L*q(3) +vs/L;
    dqdt(2) = q(3);
    dqdt(3) = kt*q(1) + mp*sin(q(2))*lp*g;
    dqdt(4) = q(5);
    dqdt(5) = mp*lp*cos(q(2))*q(3)^2 - ks*q(4) - (mb+mp)*g;
end

function M = massMatrix(~,q)
    M = [
        1 0 0 0 0;
        0 1 0 0 0;
        0 0 mp*lp^2 0 -mp*lp*sin(q(2));
        0 0 0 1 0;
        0 0 mp*lp*sin(q(2)) 0 (mb+mp)
        ];
end

2 个答案:

答案 0 :(得分:2)

最简单的解决方案是在ode45返回的每个值上重新运行您的函数。

硬解决方案是尝试将您的DotDots记录到其他地方(预先分配的矩阵甚至是外部文件)。问题是,如果ode45秘密地在奇怪的地方进行评估,你可能会得到不需要的数据点。

答案 1 :(得分:2)

由于您使用的是嵌套函数,因此可以使用其作用域规则来模拟全局变量的行为。

最简单的方法是(ab)为此目的使用output function

function solveODE

    % ....        
    %(Initialization of parameters are above this line)

    % initialize "global" variable
    rDotDot = [];

    % Specify output function 
    options = odeset(...
        'Mass', @massMatrix,...
        'OutputFcn', @outputFcn);

    % solve ODE
    [T,q] = ode45(@f, tspan,q0,options);

    % show the rDotDots    
    rDotDot



    % derivative 
    function dqdt = f(~,q)

        % q = [qDot phi phiDot r rDot]';

        dqdt = [...
            -R/L*q(1) - kb/L*q(3) + vs/L
            q(3)
            kt*q(1) + mp*sin(q(2))*lp*g
            q(5)
            mp*lp*cos(q(2))*q(3)^2 - ks*q(4) - (mb+mp)*g
        ];

    end % q-dot function 

    % mass matrix
    function M = massMatrix(~,q)
        M = [
            1 0 0 0 0;
            0 1 0 0 0;
            0 0 mp*lp^2 0 -mp*lp*sin(q(2));
            0 0 0 1 0;
            0 0 mp*lp*sin(q(2)) 0 (mb+mp)
         ];
    end % mass matrix function


    % the output function collects values for rDotDot at the initial step 
    % and each sucessful step
    function status = outputFcn(t,q,flag)

        status = 0;

        % at initialization, and after each succesful step
        if isempty(flag) || strcmp(flag, 'init')
            deriv = f(t,q);
            rDotDot(end+1) = deriv(end);
        end

    end % output function 

end 

输出函数只计算初始和所有成功步骤的导数,所以它基本上与Adrian Ratnapala建议的相同;在ode45的每个输出重新运行导数;我认为这甚至会更优雅(阿德里安+1)。

输出函数方法的优点是,您可以在运行集成时绘制rDotDot值(不要忘记drawnow!),这对于长时间运行非常有用集成。