简体   繁体   English

太阳系映射,ODE45麻烦

[英]Solar System Mapping, ODE45 trouble

The following code aims to map out the solar system by incorporating every significant body's effect on the others. 以下代码旨在通过将每个重要的身体的影响结合到其他人身上来绘制太阳系。 Of course it should result in expected orbits. 当然它应该导致预期的轨道。 In the final embedded function GravityDE it cannot read the values from PlanetVec and, because of that, cannot produce the correct new results each time. 在最终的嵌入式函数GravityDE它无法读取PlanetVec的值,因此,每次都无法生成正确的新结果。 We get the error 我们得到了错误

??? Undefined function 'GravityDE' for input arguments of type double. 

Any suggestions for how to solve this would be most welcome! 任何有关如何解决这个问题的建议都是最受欢迎的!

function Gravity1()

clear;
format long eng;
load('solar_system_data.mat');

StartTime = 0;
TimeStep = 24 * 3600 * 10;
EndTime = 24 * 3600 * 100;


TVec = StartTime:TimeStep:EndTime;
TimeStepMin = StartTime:2:TimeStep;

%Column Vectors for initial conditions
SunVec = [xposition(1), yposition(1), vx(1), vy(1),mass(1),1];
MercuryVec = [xposition(2), yposition(2), vx(2), vy(2),mass(2),2];
VenusVec = [xposition(3), yposition(3), vx(3), vy(3),mass(3),3];
EarthVec = [xposition(4), yposition(4),vx(4), vy(4),mass(4),4];
MoonVec = [xposition(10), yposition(10), vx(10), vy(10),mass(10),10];
MarsVec = [xposition(5), yposition(5), vx(5), vy(5),mass(5),5];
JupiterVec = [xposition(6), yposition(6), vx(6), vy(6),mass(6),6];
SaturnVec = [xposition(7), yposition(7), vx(7), vy(7),mass(7),7];
UranusVec = [xposition(8), yposition(8), vx(8), vy(8),mass(8),8];
NeptuneVec = [xposition(9), yposition(9), vx(9), vy(9),mass(9),9];
PlanetVec=[SunVec(1),SunVec(2),SunVec(3),SunVec(4),SunVec(5),SunVec(6);MercuryVec(1),       MercuryVec(2), MercuryVec(3), MercuryVec(4),MercuryVec(5),MercuryVec(6);VenusVec(1), VenusVec(2), VenusVec(3), VenusVec(4),VenusVec(5),VenusVec(6);EarthVec(1), EarthVec(2), EarthVec(3), EarthVec(4),EarthVec(5),EarthVec(6);MoonVec(1),MoonVec(2),MoonVec(3),MoonVec(4),MoonVec(5),MoonVec(6);MarsVec(1), MarsVec(2), MarsVec(3), MarsVec(4),MarsVec(5),MarsVec(6);JupiterVec(1), JupiterVec(2), JupiterVec(3), JupiterVec(4),JupiterVec(5),JupiterVec(6);SaturnVec(1), SaturnVec(2), SaturnVec(3), SaturnVec(4),SaturnVec(5),SaturnVec(6);UranusVec(1), UranusVec(2),UranusVec(3), UranusVec(4),UranusVec(5),UranusVec(6);NeptuneVec(1),       NeptuneVec(2), NeptuneVec(3), NeptuneVec(4),NeptuneVec(5),NeptuneVec(6)];
n=0;
while n<EndTime;
%Built in solver
[TimeVec, SunMat] = ode45(@GravityDE, TimeStepMin, SunVec);
[TimeVec, MercuryMat] = ode45(@GravityDE, TimeStepMin, MercuryVec);
[TimeVec, VenusMat] = ode45(@GravityDE, TimeStepMin, VenusVec);
[TimeVec, EarthMat] = ode45(@GravityDE, TimeStepMin, EarthVec);
[TimeVec, MoonMat] = ode45(@GravityDE, TimeStepMin, MoonVec);
[TimeVec,  MarsMat] = ode45(@GravityDE, TimeStepMin, MarsVec);
[TimeVec, JupiterMat] = ode45(@GravityDE, TimeStepMin, JupiterVec);
[TimeVec, SaturnMat] = ode45(@GravityDE, TimeStepMin, SaturnVec);
[TimeVec,  UranusMat] = ode45(@GravityDE, TimeStepMin, UranusVec);
[TimeVec, NeptuneMat] = ode45(@GravityDE, TimeStepMin, NeptuneVec);

SunXVec = SunMat (end,1);
SunYVec = SunMat (end,2);
SunVXVec = SunMat(end,3);
SunVYVec = SunMat(end,4);

MercuryXVec = MercuryMat (end,1);
MercuryYVec = MercuryMat (end,2);
MercuryVXVec = MercuryMat(end,3);
MercuryVYVec = MercuryMat(end,4);

VenusXVec = VenusMat (end,1);
VenusYVec = VenusMat (end,2);
VenusVXVec = VenusMat(end,3);
VenusVYVec = VenusMat(end,4);

EarthXVec = EarthMat (end,1);
EarthYVec = EarthMat (end,2);
EarthVXVec = EarthMat(end,3);
EarthVYVec = EarthMat(end,4);

MoonXVec = MoonMat (end,1);
MoonYVec = MoonMat (end,2);
MoonVXVec = MoonMat(end,3);
MoonVYVec =MoonMat(end,4);

MarsXVec = MarsMat (end,1);
MarsYVec = MarsMat (end,2);
MarsVXVec = MarsMat(end,3);
MarsVYVec = MarsMat(end,4);

JupiterXVec = JupiterMat (end,1);
JupiterYVec = JupiterMat (end,2);
JupiterVXVec = JupiterMat(end,3);
JupiterVYVec =JupiterMat(end,4);

SaturnXVec = SaturnMat (end,1);
SaturnYVec = SaturnMat (end,2);
SaturnVXVec = SaturnMat(end,3);
SaturnVYVec =SaturnMat(end,4);

UranusXVec = UranusMat (end,1);
UranusYVec = UranusMat (end,2);
UranusVXVec = UranusMat(end,3);
UranusVYVec =UranusMat(end,4);

NeptuneXVec = NeptuneMat (end,1);
NeptuneYVec = NeptuneMat (end,2);
NeptuneVXVec = NeptuneMat(end,3);
NeptuneVYVec =NeptuneMat(end,4);

SunVec=[SunXVec,SunYVec,SunVXVec,SunVYVec,mass(1),1];
MercuryVec = [MercuryXVec, MercuryYVec, MercuryVXVec, MercuryVYVec,mass(2),2];
VenusVec = [VenusXVec, VenusYVec, VenusVXVec, VenusVYVec,mass(3),3];
EarthVec = [EarthXVec, EarthYVec, EarthVXVec, EarthVYVec,mass(4),4];
MoonVec = [MoonXVec,MoonYVec,MoonVXVec,MoonVYVec,mass(10),10];
MarsVec = [MarsXVec, MarsYVec, MarsVXVec, MarsVYVec,mass(5),5];
JupiterVec = [JupiterXVec, JupiterYVec, JupiterVXVec, JupiterVYVec,mass(6),6];
SaturnVec = [SaturnXVec, SaturnYVec, SaturnVXVec, SaturnVYVec,mass(7),7];
UranusVec = [UranusXVec, UranusYVec,UranusVXVec, UranusVYVec,mass(8),8];
NeptuneVec = [NeptuneXVec, NeptuneYVec, NeptuneVXVec, NeptuneVYVec,mass(9),9];
PlanetVec=[SunVec(1),SunVec(2),SunVec(3),SunVec(4),SunVec(5),SunVec(6);MercuryVec(1),                MercuryVec(2), MercuryVec(3), MercuryVec(4),MercuryVec(5),MercuryVec(6);VenusVec(1),  VenusVec(2), VenusVec(3), VenusVec(4),VenusVec(5),VenusVec(6);EarthVec(1), EarthVec(2),   EarthVec(3),   EarthVec(4),EarthVec(5),EarthVec(6);MoonVec(1),MoonVec(2),MoonVec(3),MoonVec(4),MoonVec(5),MoonVec(6);MarsVec(1), MarsVec(2), MarsVec(3), MarsVec(4),MarsVec(5),MarsVec(6);JupiterVec(1),  JupiterVec(2), JupiterVec(3), JupiterVec(4),JupiterVec(5),JupiterVec(6);SaturnVec(1),  SaturnVec(2), SaturnVec(3), SaturnVec(4),SaturnVec(5),SaturnVec(6);UranusVec(1),  UranusVec(2),UranusVec(3), UranusVec(4),UranusVec(15),UranusVec(6);NeptuneVec(1),  NeptuneVec(2), NeptuneVec(3), NeptuneVec(4),NeptuneVec(5),NeptuneVec(6)];

plot (SunXVec,SunYVec,'.','Color','yellow');
hold on;
plot (MercuryXVec,MercuryYVec,'.','Color','green');
hold on;
plot (VenusXVec,VenusYVec,'.','Color','blue');
hold on;
plot (EarthXVec,EarthYVec, '.','Color', 'red');
hold on;
plot (MoonXVec,MoonYVec, '.','Color','black');
hold on;
plot (MarsXVec,MarsYVec, '.','Color','black');
hold on;
plot (JupiterXVec,JupiterYVec,'.','Color','green');
hold on;
plot (SaturnXVec,SaturnYVec, '.','Color','blue');
hold on;
plot (UranusXVec,UranusYVec, '.','Color','red');
hold on;
plot (NeptuneXVec,NeptuneYVec, '.','Color','blue');
hold on;
n=n+TimeStep;
end

function dYVec = GravityDE (TimeStep, YVec,PlanetVec)
load('solar_system_data.mat');
GravConst = 6.67259e-11;
Xi = YVec(1);
Yi = YVec(2);
VXi = YVec(3);
VYi = YVec(4);
Massi=YVec(5);
BodyName=YVec(6);

AccXtotal=0;
AccYtotal=0;
j=1;
while j<=10

Massj=PlanetVec(j,5);
Yj=PlanetVec(j,2);
Xj=PlanetVec(j,1);



RangeSq = (Xi-Xj).^2 + (Yi-Yj).^2;
if RangeSq==0
    AccMag=0;
    Theta = atan2(Yi-Yj,Xi-Xj);
    AccX = -AccMag .* cos (Theta);
    AccY = -AccMag .* sin (Theta);
    j=j+1;
    AccXtotal=AccXtotal+AccX;
    AccYtotal=AccYtotal+AccY;
else
    Theta = atan2(Yi-Yj,Xi-Xj);
    AccMag = (GravConst .* Massj ./ RangeSq);
    AccX = -AccMag .* cos (Theta);
    AccY = -AccMag .* sin (Theta);
    j=j+1;
    AccXtotal=AccXtotal+AccX;
    AccYtotal=AccYtotal+AccY;
    VXi=VXi+AccXtotal.*TimeStep;
    VYi=VYi+AccYtotal.*TimeStep;
end

dYVec = [VXi; VYi; AccXtotal; AccYtotal;Massi;BodyName];

end

Thanks!! 谢谢!!

OK, here we go. 好的,我们走了。 It's going to be a LONG answer, and it will probably be over-complete, but I think it'll be valuable also for future visitors. 这将是一个很长的答案,它可能会过于完整,但我认为它对未来的访问者也很有价值。

The force on a celestial body of mass M due to another celestial body of mass m equals 由于另一个质量为m的天体,质量为M的天体上的力等于

F = -GMm / r² F = -GMm /r²

where r is the distance between the two bodies. 其中r是两个物体之间的距离。 That is how we all learn Newton's equation in high school (I hope, anyway...). 这就是我们在高中学习牛顿方程式的方法(我希望,无论如何......)。 The basic equation above is somewhat flawed, for reasons I indicated in my comment above. 由于我在上面的评论中指出的原因,上面的基本等式存在一些缺陷。 Also, it is incomplete in the context of more-than-two celestial bodies. 而且,在超过两个天体的背景下,它是不完整的。

First, GM is replaced by something that can actually be measured, μ -- a body's standard gravitational parameter . 首先, GM被实际可以测量的东西取代, μ--身体的标准引力参数 Second, calculations need to be easy to do in an arbitrary coordinate system. 其次,在任意坐标系中都需要很容易进行计算。 Third, the direction of the force is not included in the equation above. 第三,力的方向不包括在上面的等式中。 Fourth, the acceleration of a celestial body is usually what matters, not the force. 第四,天体的加速通常是重要的,而不是力。

All this can be included by re-phrasing the equation as 所有这些都可以通过将等式重新表述为包括在内

i = Σ j≠i μ j r ij / | R I =ΣĴ≠我 μĴ R ij / | r ij r ij

where boldface letters indicate vectors, r is a position vector wrt some arbitrary coordinate system, r ij = r i - r j is the vector from body i to body j , and the double-dots are Newton's double-fluxions (equal to Leibniz' d²/dt²). 其中粗体字母表示向量, r是某个任意坐标系的位置向量, r ij = r i - r j是从身体i到身体j的向量,双点是牛顿的双流量(等于Leibniz' D²/dt²)。

In words: the instantaneous directed acceleration of body i due to the gravitational effects of all other bodies j , is the summation of the gravitational parameters μ j , divided by the squared distance between body i and j , and multiplied by the vector between the two bodies scaled to unity, over all other bodies j in the system (you see why we invented Mathematical notation? :) 在词:身体的i由于所有其他机构j的引力效应瞬时方向上的加速度,是重力参数的总和μĴ,由身体状况之间的平方距离除以ij,并且通过这两者之间的矢量乘以在系统中所有其他身体j上的身体缩小为统一(你知道为什么我们发明了数学符号吗?:)

This equation describes a system of j second-order differential equations, which cannot be solved analytically (in an easily computable, closed form anyway) and must therefore be solved numerically. 该等式描述了j个二阶微分方程的系统,其不能通过分析求解(无论如何以易于计算的闭合形式)并且因此必须在数值上求解。 Matlab's ode45 can do that, although its accuracy leaves something to be desired if you want to simulate the planet's orbits for several dozens of years or more (especially mercury's orbit is notoriously difficult to compute accurately numerically). Matlab的ode45可以做到这一点,虽然如果你想模拟几十年或更长时间的行星轨道(特别是汞的轨道很难用数字精确计算),它的准确性还有待提高。

Anyway, you solve this with ode45 as follows. 无论如何,你用ode45解决这个ode45如下。 Define 限定

y 0 = [ r 1 1 r 2 2 ... r j j ] T ÿ0 = [R 1 R 1 R 2 R 2 ...řĴ - [R j]的 Ť

which is the collection of initial state vectors of all j bodies. 这是所有j体的初始状态向量的集合。 In code (independent of input sizes): 在代码中(与输入大小无关):

y0 = [xposition(:) yposition(:) vx(:) vy(:)].';  
y0 = y0(:);

Note that you do not need to give all the state vectors individual names. 请注意,您不需要把所有的状态矢量个人的名字。 This I also strongly discourage; 我也强烈反对; how would you go about integrating the asteroid belt? 你会如何整合小行星带? Would you really give ~500.000 variable names to all the individual state vectors? 你真的会给所有单个状态向量提供~500.000个变量名吗? No--use Matlab's vector/matrix nature to your advantage. 不 - 使用Matlab的矢量/矩阵特性对您有利。

You can probably prevent the mess above by defining your xposition and yposition (and speeds) not separately, but together in a single vector. 你可以通过不单独定义xpositionyposition (和速度)来防止上面的混乱,但是在一个向量中一起定义。

The ode45 integrator works by computing ode45集成商通过计算工作

= [ 1 1 2 2 ... j j ] T Y = [R 1 R 1 R 2 R 2 ...řĴ - [R j]的 Ť

from an input y at each iteration. 从每次迭代的输入y开始。 It is here that the modified Newton's equation above comes into play; 正是在这里,上面修改过的牛顿方程起作用了; to compute the double-fluxions j . 计算双fluxions [R 学家 In code: 在代码中:

% collect data     
r = [y(1:4:end) y(2:4:end)];  % X/Y positions
V = [y(3:4:end) y(4:4:end)];  % Vx/Vy speeds

% initialize output
ydotdot = zeros(size(y));
ydotdot(1:4:end) = V(:,1);  % we already know the first half;
ydotdot(2:4:end) = V(:,2);  % it's simply equal to the speeds

% Compute all accelerations. 
% This is where ALL the computational burden is -- when optimizing 
% for speed, this is where to start!
sz   = size(r,1);
accx = zeros(sz);
accy = zeros(sz);
for ii = 1:sz
    ri = r(ii,:);
    for jj = ii+1:sz
        rij = ri - r(jj,:);
        sc  = (rij*rij.')^(-3/2);
        accx(jj,ii) = rij(1) * sc;
        accy(jj,ii) = rij(2) * sc;
    end
end

accx = bsxfun(@times, -mu(:), accx-accx.');
accy = bsxfun(@times, -mu(:), accy-accy.');

% insert accelerations
ydotdot(3:4:end) = sum(accx);
ydotdot(4:4:end) = sum(accy);

The way you were doing it was to compute the double-fluxion of the position of the planet, while the other planets were in their initial positions; 你这样做的方法是计算行星位置的双重流动,而其他行星处于初始位置; you wanted to pass PlanetVec , the collection of initial statevectors (that I've called y 0 ) into GravityDE , and compute distances and accelerations of the planet wrt that vector. 你想把PlanetVec ,初始状态向量(我称之为y 0 )的集合传递给GravityDE ,并计算该向量的行星距离和加速度。

This is or course incorrect -- this will only move one planet, while keeping the other planets still. 这当然是不正确的 - 这只会移动一个行星,同时保持其他行星不动。 That's not how the Solar system works :p Now you might argue that it doesn't matter much, since the planets move so slowly, but that is true only for the outer planets; 这不是太阳系的工作原理:p现在你可能会认为它并不重要,因为行星移动的速度很慢,但这只适用于外行星; Mercury's influence on Venus' orbit for example is grossly miscalculated that way. 例如,水星对金星轨道的影响严重错误估计。

Now you know the general principles. 现在你知道了一般原则。 DISCLAIMER : I've written this all from memory without much checking, so I might have missed a minus sign here and there. 免责声明 :我在没有太多检查的情况下从内存中写下这些内容,所以我可能会在这里和那里错过一个减号。 I think it's a good exercise for you to understand and check everything I did here. 我认为这是一个很好的练习,让你理解并检查我在这里所做的一切。

Now, a complete, functional, copy-pastable summary: 现在,一个完整的,功能性的,可复制的摘要:

function Gravity1

    % NOTE: 'clear' has no meaning at the start of a function; a function
    % has its own variable space, meaning it is empty to begin with.

    % NOTE: this assumes you put have all the planetary mu's inside this datafile
    load('solar_system_data.mat');

    % NOTE: ode45 chooses its own time steps; its an adaptive method.
    % Passing it custom time steps is hopelessly inefficient.
    t0   = 0;
    tend = 24 * 3600 * 100;

    % re-format initial vectors
    y0 = [xposition(:) yposition(:) vx(:) vy(:)].';  
    y0 = y0(:);

    % perform integration 
    [t y] = ode45(@d2ydt2, [t0 tend], y0);

    % and do plot
    h = figure; hold on % NOTE: only a single 'hold on' is needed to turn it on :) 
    plot(y(:,1),y(:,2), 'y.');    % Sun
    plot(y(:,1),y(:,2), 'g.');    % Mercury
    plot(y(:,1),y(:,2), 'b.');    % Venus
    plot(y(:,1),y(:,2), 'r.');    % Earth
    plot(y(:,1),y(:,2), 'k.');    % Mars
    plot(y(:,1),y(:,2), 'g.');    % Jupiter
    plot(y(:,1),y(:,2), 'b.');    % Saturn
    plot(y(:,1),y(:,2), 'r.');    % Uranus
    plot(y(:,1),y(:,2), 'b.');    % Neptune


    % It's easiest to put the differential equation in a nested function    
    function ydotdot = d2ydt2(~,y)

        % rename data     
        r = [y(1:4:end) y(2:4:end)];  % X/Y positions
        V = [y(3:4:end) y(4:4:end)];  % Vx/Vy speeds

        % initialize output
        ydotdot = zeros(size(y));
        ydotdot(1:4:end) = V(:,1);  % we already know the first half;
        ydotdot(2:4:end) = V(:,2);  % it's simply equal to the speeds

        % Compute all accelerations. 
        % This is where ALL the computational burden is -- when optimizing 
        % for speed, this is where to start!
        sz   = size(r,1);
        accx = zeros(sz);
        accy = zeros(sz);
        for ii = 1:sz
            ri = r(ii,:);
            for jj = ii+1:sz
                rij = ri - r(jj,:);
                sc  = (rij*rij.')^(-3/2);
                accx(jj,ii) = rij(1) * sc;
                accy(jj,ii) = rij(2) * sc;
            end
        end

        accx = bsxfun(@times, -mu(:), accx-accx.');
        accy = bsxfun(@times, -mu(:), accy-accy.');

        % insert accelerations
        ydotdot(3:4:end) = sum(accx);
        ydotdot(4:4:end) = sum(accy);

    end

end

Note that I have not even looked at why your original function failed to run. 请注意,我甚至没有看到为什么你的原始功能无法运行。 I bet that once you get this running, it doesn't really matter anymore. 我敢打赌,一旦你开始运行,它就不再重要了。

Without solar_system_data.mat , it's hard to debug your code, but the problem is that your are not passing PlanetVec to your function 没有solar_system_data.mat ,很难调试你的代码,但问题是你没有将PlanetVec传递给你的函数

If my memory serves me well, you should try 如果我的记忆很好,你应该试试

[TimeVec, SunMat] = ode45(@(t,y)GravityDE(t,y,PlanetVec), TimeStepMin, SunVec);

Please read about parameterizing functions 请阅读有关参数化功能的信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM