我用质量弹簧和双摆来模拟一个(有点奇怪的)系统的运动方程,我有一个质量矩阵和函数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
答案 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
!),这对于长时间运行非常有用集成。