Matlab中的摆动弹簧ODE系统-如何使位置向量跟随路径?

Matlab中的摆动弹簧ODE系统-如何使位置向量跟随路径?,matlab,ode,numerical-integration,Matlab,Ode,Numerical Integration,我对Matlab很陌生。 我有一个脚本,使用了ode45,在Matlab上显示了一个带质量的摆动弹簧在三维空间中的运动。这个程序几乎达到了我想要的效果。现在钻石的密度显示了弹簧的实际速度(除了ode45采集个人最喜欢的数字样本时),速度几乎与函数的步长(至少与我的计算机运行代码的速度)一致。我想做的是让我在代码中注释掉的位置向量只显示在质量的瞬时位置,也就是曲线的端点,而不是钻石显示的每个点。我四处寻找帮助,但我所尝试的一切似乎都会导致错误。如果有人能给我指出正确的方向,我将不胜感激。请试着运行

我对Matlab很陌生。 我有一个脚本,使用了
ode45
,在Matlab上显示了一个带质量的摆动弹簧在三维空间中的运动。这个程序几乎达到了我想要的效果。现在钻石的密度显示了弹簧的实际速度(除了
ode45
采集个人最喜欢的数字样本时),速度几乎与函数的步长(至少与我的计算机运行代码的速度)一致。我想做的是让我在代码中注释掉的位置向量只显示在质量的瞬时位置,也就是曲线的端点,而不是钻石显示的每个点。我四处寻找帮助,但我所尝试的一切似乎都会导致错误。如果有人能给我指出正确的方向,我将不胜感激。请试着运行这个程序,你会明白我的意思,也可以玩转函数的参数

function elasticPendulum(totalTime)
time=1;
totalTime=20
X=1
Vx=0
Y=0
Vy=0
Z=1.1
Vz=0
w=3;
g=9;
l=1;
while (time<totalTime)
    tspan=[0,time];
    x0=[X,Vx,Y,Vy,Z,Vz];
    [t,x]=ode45(@F,tspan,x0);
    plot3(x(:,1),x(:,3),x(:,5),'dk'), axis([-2 2 -2 2 -10 2]);
    grid on;
    o=[0, 0, 0];
    Xeq=[0, 0, -(g/(w^2)+l)];
    arrow(o,Xeq,'Length',5);
    %{ 
    Xt=[x(:,1) x(:,3) x(:,5)]
    arrow(o,Xt,'Length',5);
    %}
    time=time+.1*(((x(2))^2+(x(4))^2+(x(6))^2)^(1/2))
    pause(.1);
end

    function xprime=F(t,x)
    r=sqrt(x(1)^2+x(3)^2+x(5)^2);
    xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];
    end

end
功能弹性摆锤(总时间)
时间=1;
总时间=20
X=1
Vx=0
Y=0
Vy=0
Z=1.1
Vz=0
w=3;
g=9;
l=1;

而(time我认为您只需将
Xt
设置为该值,就可以完成您想要的内容,这样每次迭代只绘制最后一个向量:

Xt = [x(end,1) x(end,3) x(end,5)];
此外,您还提到“除了ode45采集个人最喜爱的数字样本外”,一切正常。您可以通过更改
tspan
,告诉
ode45
使用固定步长输出:

tspan = 0:dt:time;
其中
dt=1/time
(或者您可以使用)。这与使用固定步长解算器不同–阅读可能会对此有所了解

我认为您没有正确地更新动画。您更新了时间,但没有更新初始条件。因此,在
while
循环的每次迭代中,您都在相同的路径上进行积分。是否有理由调整每次迭代的结束时间?您是否试图找到振荡周期或其他什么

此外,您的动画方法相当粗糙/低效。您应该了解可通过为Matlab的ODE解算器设置的。特别是
'OutputFcn'
。您甚至可以使用和/或查看一些内置输出函数的代码–例如,键入
编辑odeplot
编辑odephas3
>在您的命令窗口中。以下是我为您的案例创建的一个简单输出函数:

function elasticPendulum
totalTime = 20;
stepsPerSec = 10;
X = 1; Vx = 0;
Y = 0; Vy = 0;
Z = 1.1; Vz = 0;
w = 3; g = 9; l = 1;

opts = odeset('OutputFcn',@(t,x,flag)arrowplot(t,x,flag,w,l,g));
tspan = linspace(0,totalTime,totalTime*stepsPerSec);
x0 = [X,Vx,Y,Vy,Z,Vz];
ode45(@(t,x)F(t,x,w,l,g),tspan,x0,opts);

function xprime=F(t,x,w,l,g)    %#ok<INUSL>
r=sqrt(x(1)^2+x(3)^2+x(5)^2);
xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];

function status=arrowplot(t,x,flag,w,l,g)   %#ok<INUSL>
persistent h; % Handle for moving arrow
status = 0;
o = [0, 0, 0];
switch flag
    case 'init'
        axis([-2 2 -2 2 -10 2]); grid on; hold on;
        Xeq = [0, 0, -(g/(w^2)+l)];
        arrow(o,Xeq,'Length',5);
        plot3(x(1,:),x(3,:),x(5,:),'dk');  % Initial position
        Xt = [x(1,end) x(3,end) x(5,end)];
        h = arrow(o,Xt,'Length',5);        % Initial arrow, get handle
    case 'done'
        hold off; status = 1;
    otherwise
        plot3(x(1,:),x(3,:),x(5,:),'dk');        % Plot new positions
        Xt = [x(1,end) x(3,end) x(5,end)];
        arrow(h,'Start',o,'Stop',Xt,'Length',5); % Update arrow
        pause(0.1);
end
功能弹性摆
总时间=20;
stepsPerSec=10;
X=1;Vx=0;
Y=0;Vy=0;
Z=1.1;Vz=0;
w=3;g=9;l=1;
opts=odeset('OutputFcn',@(t,x,flag)箭头图(t,x,flag,w,l,g));
tspan=linspace(0,totalTime,totalTime*stepsPerSec);
x0=[X,Vx,Y,Vy,Z,Vz];
ode45(@(t,x)F(t,x,w,l,g),tspan,x0,opts);
函数xprime=F(t,x,w,l,g)%#ok
r=sqrt(x(1)^2+x(3)^2+x(5)^2);
xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];
功能状态=箭头图(t、x、标志、w、l、g)%#正常
永久h;%移动箭头的句柄
状态=0;
o=[0,0,0];
开关标志
案例“init”
轴([-22-22-102]);网格打开;保持;
Xeq=[0,0,-(g/(w^2)+l)];
箭头(o,Xeq,'Length',5);
图3(x(1,:)、x(3,:)、x(5,:)、‘dk’;%初始位置
Xt=[x(1,结束)x(3,结束)x(5,结束)];
h=箭头(o,Xt,'Length',5);%初始箭头,获取句柄
案例“完成”
暂停;状态=1;
否则
绘图3(x(1,:)、x(3,:)、x(5,:)、‘dk’);%绘图新位置
Xt=[x(1,结束)x(3,结束)x(5,结束)];
箭头(h,'Start',o,'Stop',Xt,'Length',5);%Update arrow
暂停(0.1);
结束
每次迭代时对
plot3
的调用(在
arrowplot
中的
案例)由于添加新的高级绘图对象,仍然效率低下,占用更多内存。更好/更快的方法是从第一次调用
plot3
获取句柄,然后使用
set
get
添加新数据点。有关如何操作,请参阅
odeplot
odephas3
的代码(有点高级)


请注意,我是如何通过匿名函数而不是创建子函数来传递参数的。这是一个风格问题。

我尝试过对代码进行一些格式化。也许您注意到它没有正确显示?您应该检查它是否仍然正确。