将额外的可变参数传递给 ode15s 函数 (MATLAB)

Pass extra variable parameters to ode15s function (MATLAB)

我正在尝试在 MATLAB 中求解常微分方程组。

我有一个简单的等式: dy = -k/M *x - c/M *y+ F/M。

这是在我的 ode 函数 test2.m 中定义的,取决于值 X 和 t。我想用自定义函数 squaresignal.m 生成的信号触发 'F'。这里的输出是变量 u,范围从 0 到 1,因为它是一个平滑的重函数。 - 想想方波。 squaresignal.m 中的输入是 t 和 f。

u=squaresignal(t,f)

这些值将在我的函数 test2 中使用,以启用或禁用值为 u==1(启用)的变量 'F'。禁用所有其他值。

我的 ode 函数 test2.m 读取:

function dX = test2(t ,X, u)
x = X (1) ;
y = X (2) ;

M = 10;
k = 50;
c = 10;
F = 300;

if u == 1
    F = F;
else
    F = 0,
end

dx = y ;
dy = -k/M *x - c/M *y+ F/M ;

dX = [ dx dy ]';
end

我的运行脚本是:

clc
clear all

tstart = 0;
tend = 10;
tsteps = 0.01;

tspan = [0 10];
t = [tstart:tsteps:tend];
f = 2;

u = squaresignal(t,f)

for ii = 1:length(u)
    options=odeset('maxstep',tsteps,'outputfcn',@odeplot);
    [t,X]=ode15s(@(t,X)test2(t,X,u(ii)),[tstart tend],[0 0],u);
end


figure (1);
plot(t,X(:,1))

figure (2);
plot(t,X(:,2));

但是,for 循环似乎并没有什么神奇之处。当 u==1 时,我仍然只得到 F=0,而不是 F=F。而且我知道,有时 u 等于 1,因为 squaresignal.m 的输出对我来说是可见的。

所以真正的问题是这个。我如何正确地将我的变量 u 传递到我的函数 test2.m,并在那里使用它来触发 F?是否有可能 squaresignal.m 应该在 odefunction test2.m 内?

这是我将变量 coeff 传递给微分方程的示例:

function [T,Q] = main()
  t_span = [0 10];
  q0 = [0.1; 0.2];        % initial state
  ode_options = odeset(); % currently no options... You could add some here
  coeff = 0.3;            % The parameter we wish to pass to the differential eq.

  [T,Q] = ode15s(@(t,q)diffeq(t,q,coeff),t_span,q0, ode_options);
end

function dq = diffeq(t,q,coeff)
  % Preallocate vector dq
  dq = zeros(length(q),1);

  % Update dq:
  dq(1) = q(2);
  dq(2) = -coeff*sin(q(1));
end

编辑: 这可能是问题所在吗?

tstart = 0;
tend = 10;
tsteps = 0.01;

tspan = [0 10];
t = [tstart:tsteps:tend];
f = 2;

u = squaresignal(t,f)

在这里创建一个时间向量t,它与ODE求解器返回的时间向量无关!这意味着起初我们有 t[2]=0.01 但是一旦你 运行 你的 ODE 求解器,t[2] 可以是任何东西。所以是的,如果你想根据时间加载外部信号源,那么你需要从微分方程中调用你的 squaresignal.m 并传递求解器的当前时间 t!您的代码应如下所示(请注意,我现在将 f 作为 diffeq 的附加参数传递):

function dX = test2(t ,X, f)
x = X (1) ;
y = X (2) ;

M = 10;
k = 50;
c = 10;
F = 300;

u = squaresignal(t,f)
if u == 1
    F = F;
else
    F = 0,
end

dx = y ;
dy = -k/M *x - c/M *y+ F/M ;

dX = [ dx dy ]';
end

但是请注意,matlab 的 ODE 求解器根本不喜欢您在这里所做的事情。您正在彻底(即非平稳地)改变系统的动态。你应该做的是使用以下之一:

a) events 如果您想根据集成变量 x

触发某些行为(如终止)

b) 如果您想根据时间 t 触发行为,您应该将积分分成不同的部分,其中微分方程在一个部分中不会发生变化。然后,您可以使用当前状态和时间作为 ode15s 的下一个 运行 的 x0t0 来恢复集成。当然这只适用于你的外部信号源 u 是一些简单的东西,比如阶跃函数或方波。在方波的情况下,您只会对波不跳跃的时间跨度进行积分。然后恰好在跳跃的时候,你开始用改变的微分方程进行另一个积分。