【问题标题】:How to fix assignment error using ode45 in MatLab (line 488 of ode45 function)如何在 MatLab 中使用 ode45 修复分配错误(ode45 函数的第 488 行)
【发布时间】:2019-05-19 23:45:18
【问题描述】:

我正在尝试编写一个使用ode45 的脚本,以便整合卫星在火星附近双曲线轨迹上的运动方程

我需要整合环绕地球的整个通道:从 SOI 半径 (576000km) 开始,向地球前进,然后穿过大气层,直到卫星到达“opposite”大气层边界(设置为 @987654324 @从表面上看)。

当它在输入中接收到高于大约200000 秒的tspan(我需要大约400000 秒)时,Matlab 会给我这个消息:

'无法执行赋值,因为左边的大小是 4×2,右侧大小为 4×5。它说 error happens in line 488 of Ode45.

我搜索了一些类似的案例,但我找不到任何东西,我不知道如何使用条件断点来找出复杂函数(例如 ode45)的某些内容。我还使用“odeset”尝试了不同的选项,但没有任何改变。我不知道错误可能出在哪里。

这是脚本,我在其中使用了两个附加函数来获取一些参数:

Vinf=[2.7 4 6 8];
mu_m=42828;
R_msoi=.576e6;

[afas,efas,pfas]=parasint(Vinf);

an_vera0=zeros(1,length(Vinf));
Vr0=zeros(1,length(Vinf));
Vt0=zeros(1,length(Vinf));

for j=1:length(Vinf)

    c_tstar0=(1/efas(j))*((pfas(j)/R_msoi)-1);
    an_vera0(j)=-acos(c_tstar0);
    s_tstar0=sin(an_vera0(j));
    Vr0(j)=sqrt(mu_m/pfas(j))*efas(j)*s_tstar0;
    Vt0(j)=sqrt(mu_m/pfas(j))*(1+efas(j)*c_tstar0);

end

ti=time(an_vera0,efas,afas,mu_m);

for n=1:length(ti)

    I=(0:3600:ti(n));
    options=odeset('Vectorized','on','RelTol',1e-8,'AbsTol',1e-9);
    [t,Y]=ode45(@(t,y) eqMotoCur(t,y),I,y0,options);

end

这是“parasint”函数:

function [afas,efas,pfas]=parasint(Vinf)

mu_m=42828;
R_m=3396.2;
Rp0=R_m+400;
Rpf=R_m+50;
a0=zeros(1,length(Vinf));
e0=zeros(1,length(Vinf));
p0=zeros(1,length(Vinf));
afas=zeros(1,length(Vinf));
efas=zeros(1,length(Vinf));
pfas=zeros(1,length(Vinf));

for j=1:length(Vinf)
    a0(j)=(-mu_m)/(Vinf(j)^2);
    e0(j)=1-Rp0/a0(j);
    p0(j)=a0(j)*(1-e0(j)^2);

    c(1)=p0(j);
    c(2)=Rpf*(1-e0(j)^2);
    c(3)=Rpf*(1-e0(j)^2)-p0(j);
    Efas=roots(c);
    ind=(Efas>1 & isreal(Efas));
    efas(j)=Efas(ind);
    afas(j)=Rpf/(1-efas(j));
    pfas(j)=afas(j)*(1-efas(j)^2);
end

这是“time”函数:

function [ti] = time(an_vera0,efas,afas,mu_m)

ti=zeros(1,length(an_vera0));
for j=1:length(an_vera0)
    F=2*atanh(sqrt((efas(j)-1)/(efas(j)+1))*tan(an_vera0(j)/2));
    T=sqrt((-afas(j))^3/mu_m)*(efas(j)*sinh(F) - F);
    ti(j)=-2*T;
end

这是 ode45 的输入函数:

function [dydt] = eqMotoCur(t,y)
R_m=3396.2;
mu_m=42828;
Cd=2.2;
S=7.065e-6;
m=3699.046;
wE=0.24117/R_m;
if abs(y(1))>R_m+250 && y(3)>0
    dydt(1:4)=0;
else
    dydt=zeros(4,1);
    dydt(1)=y(3);
    dydt(2)=y(4)/y(1);
    dydt(3)=(-mu_m/(y(1)^2))+((y(4)^2)/y(1))-(.5*Cd)*(S/m)*...
    (dens(y(1)-R_m))*(sqrt((y(3)^2)+(y(4)-(wE*y(1)))^2))*y(3);
    dydt(4)=-(y(4)*(y(3)/y(1)))-(.5*Cd)*(S/m)*...
    (dens(y(1)-R_m))*(sqrt((y(3)^2)+(y(4)-(wE*y(1)))^2))*...
    (y(4)-(wE*y(1)));
end
end

这是通过大气插值数据的“dens”函数:

function [rho] = dens(z)

load Density.mat h d
d=d*10^9;

if any(h)==abs(z)
    j=h==abs(z);
    rho=d(j);
elseif abs(z)<250
    c_tot=(find(h>=abs(z)));
    c=c_tot(1);
    H=-(h(c)-h(c-1))/(log(d(c)/d(c-1)));
    rho=d(c-1)*exp(-(abs(z)-h(c-1))/H);
else
    rho=0;
end

end

这是 Matlab 给我的错误:

无法执行赋值,因为左边的大小是 4×2,右侧大小为 4×5。

ode45 (line 488) 中的错误 yout(:,idx) = yout_new;

MainCur (line 59) 中的错误 [t,Y]=ode45(@(t,y) eqMotoCur(t,y),I,y0,options);

提前谢谢你。

【问题讨论】:

    标签: matlab runtime-error ode45 tspan


    【解决方案1】:
    • ode45(@(t,y) eqMotoCur(t,y),I,y0,options) 返回一个 5 by 4 矩阵
    • [t,Y]是一个2 by 4矩阵
    • 因此尺寸不匹配为5 by 4 # 2 by 4
    • [t,Y] 替换为[t,Y, ~,~, ~]
    • 只保留你想要的前两个变量,忽略其余的 通过使用~
    [t,Y, ~,~, ~]=ode45(@(t,y) eqMotoCur(t,y),I,y0,options);
    

    确保在运行ode45之前先定义y0

    函数dens(z) 应该在eqMotoCur(t,y) 中定义,因为您需要它在eqMotoCur(t,y) 中执行一些计算

    function [dydt] = eqMotoCur(t,y)
        %% define dens here 
        function [rho] = dens(z)
    
            load Density.mat h d
            d=d*10^9;
    
            if any(h)==abs(z)
                j=h==abs(z);
                rho=d(j);
            elseif abs(z)<250
                c_tot=(find(h>=abs(z)));
                c=c_tot(1);
                H=-(h(c)-h(c-1))/(log(d(c)/d(c-1)));
                rho=d(c-1)*exp(-(abs(z)-h(c-1))/H);
            else
                rho=0;
            end
    
        end
        %% Now start eqMotoCur
        R_m=3396.2;
        mu_m=42828;
        Cd=2.2;
        S=7.065e-6;
        m=3699.046;
        wE=0.24117/R_m;
        if (abs(y(1))>R_m+250 && y(3)>0) ||y(1)==0
            dydt(1:4)=0;
        else
            dydt=zeros(4,1);
            dydt(1)=y(3);
            dydt(2)=y(4)/y(1);
            dydt(3)=(-mu_m/(y(1)^2))+((y(4)^2)/y(1))-(.5*Cd)*(S/m)*...
            (dens(y(1)-R_m))*(sqrt((y(3)^2)+(y(4)-(wE*y(1)))^2))*y(3);
            dydt(4)=-(y(4)*(y(3)/y(1)))-(.5*Cd)*(S/m)*...
            (dens(y(1)-R_m))*(sqrt((y(3)^2)+(y(4)-(wE*y(1)))^2))*...
            (y(4)-(wE*y(1)));
        end
    end
    

    主要问题是时间t,如果在 second 这就是 ode45 卡住的地方。
    交替将秒转换为 小时(除以 3600),它会起作用。结果也是 获得的是 struct 数据类型,其中 x 表示 t,y 表示 y。让我们 说 t = sol{1}.xy = sol{1}.y
    因为数组将是 更改每次迭代我使用cell 将它们分开保存

    主要代码如下

    Vinf=[2.7 4 6 8];
    mu_m=42828;
    R_msoi=.576e6;
    
    [afas,efas,pfas]=parasint(Vinf);
    
    an_vera0=zeros(1,length(Vinf));
    Vr0=zeros(1,length(Vinf));
    Vt0=zeros(1,length(Vinf));
    
    for j=1:length(Vinf)
    
        c_tstar0=(1/efas(j))*((pfas(j)/R_msoi)-1);
        an_vera0(j)=-acos(c_tstar0);
        s_tstar0=sin(an_vera0(j));
        Vr0(j)=sqrt(mu_m/pfas(j))*efas(j)*s_tstar0;
        Vt0(j)=sqrt(mu_m/pfas(j))*(1+efas(j)*c_tstar0);
    
    end
    
    ti=time(an_vera0,efas,afas,mu_m);
    ti = ti/3600;
    sol = cell(1,4);
    for n=1:length(ti)
       y0=[.576e6; an_vera0(n); Vr0(n) ;Vt0(n)];
    
    
        I=0:1:ti(n);
    
        options=odeset('Vectorized','on','RelTol',1e-8,'AbsTol',1e-9);
    
    sol{n} = ode45(@eqMotoCur,I, y0,options);
    
    end
    

    【讨论】:

    • 我试过了,但没用。无论ode45 的输出如何,似乎错误都发生在中间步骤中。当我使用低于200000 秒的tspan 进行修改时,它会显示Output argument "varargout{4}" (and maybe others) not assigned during call to "ode45".。我真的不明白tspan 和我的分配错误之间的关系。
    • 好吧,我在你的代码中看不到y0。上传y0我帮你查一下
    • 你说得对,我没注意到。它在主脚本的最后一个for 循环中。 y0=[.576e6;an_vera0(n);Vr0(n);Vt0(n)];
    • 还在eqMotoCur 内定义函数benz。我更新了我的答案,检查一下。
    • 我还需要Density.mat h d 为你运行代码
    【解决方案2】:

    我发现问题出在我在EqMotoCur 函数中手动编写的停止条件下,但考虑到我的目的,我无法按照您建议的方式纠正它:计算会停止在半径变为零的那一刻。 因此,我删除了该条件并编写了一个事件函数用作停止条件。我的修改并没有解决“除法可能为零”的问题,所以我还在EqMotoCur 中切换了dydty 的前两个元素。通过这种方式,“计算半径”(y(2) 或现在sol{1}.y 中的第二行)将永远不会变得既不为零也不低于火星半径,并且将使用tspan 的任何值(以秒为单位)真实地模拟双曲线轨迹。 这是我使用的事件函数,如果有人感兴趣的话(它不适应cell 形式,因为我没有时间适应它):

    function [value, isterminal, direction] = atmexit(t, y)
    
        R_m=3396.2;
        value=((y(2)>=R_m+250) && (y(3)>0))-0.5;
        isterminal=1;
        direction=0;
    
    end
    

    无论如何,如果没有你的帮助和时间,我永远做不到,非常感谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-07
      • 2018-07-03
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 1970-01-01
      相关资源
      最近更新 更多