如何写出三体的MATLAB程序-代码篇

如何写出三体的MATLAB程序-代码篇

写在前面

在上文当中我们已经对三个物体之间的受力进行了分析,也说明了在时间t下的加速度、速度和位移的计算方式。

本篇中将根据上一篇的公式来写出对应的代码,并且详细说明一下如何去构建一个程序的框架。

本文所有代码均在我的Github中存有备份,可下载后直接运行,点击Github: HanpuLiang/Three-Body-by-MATLAB即可进入。

构建框架

基本变量

我们首先要确定,物体本身具有哪些物理量?

质量、加速度、速度、坐标。

其中加速度和坐标为矢量,当在计算过程当中可以将其正交分解为xy轴的标量。

其余的量我们还可以设置一下,诸如:物体运动的时间长度、我们计算所需要的时间间隔、万有引力常数等。

对于我们要做出的图像大小也需要设置一下,比如说x轴范围,y轴范围等。

程序流程

初始化

首先需要初始化,确定三个物体在初始状态的情况:初始坐标、初始速度(大小与方向)。所以一共需要三个量:坐标、速度大小、速度相对x轴角度。

物体的加速度可以直接由万有引力公式计算出来,为了计算方便,需要将其正交分解与叠加。

随着时间演变

物体开始运动了,但是因为我们无法给出一段连续的时间,只能计算在极小的时间间隔\Delta t之后物体所在的位置。

所以在t\to t+Delta t时间,首先计算出当前位置的加速度,然后根据这个加速度算出当前的速度,再根据这个速度算出经历过\Delta t时间后的位移变化量,再将这个位移变化量叠加到t的位置上。

这样子就完成了一个循环。

作图

之前按道理,我们应该将每一个时间点的值放在一个矩阵内,这样子我们就可以得到随之间变化的所有物理量。

这样子我们就可以直接做出随着时间变化的各个物理量的图,如t-vt-a以及t-\theta等。

如果我们想要做出小球的运动图,那就需要t时刻及其之前(做出尾迹)的数据进行作图。

实际代码

基本变量-代码

首先是初始化

%% 初始条件
% 初始条件为以圆心为(0, 0)半径r的圆上有三个等质量的点
r = 10;
% 坐标(等边三角形)
pos0 = [0, r; r/2*sqrt(3), -r/2; -r/2*sqrt(3), -r/2];
% 速度大小
v0 = [6, 6, 6];
% 速度方向(x轴正方向为参考)
theta0 = [0, 4*pi/3, 2*pi/3];

%% 参数设置
global G dt m x_min x_max y_min y_max time_end isOutVideo;
% 结束时间
time_end = 2;
% 时间间隔
dt = 0.05;
% 万有引力系数,随便设置的
G = 1;
% 质量
m = [1000, 1000, 1000];
% 小球个数
N = length(v0);
% 图像边界
x_min = -25;
x_max = -x_min;
y_min = x_min;
y_max = -y_min;
% 是否输出视频图像
isOutVideo = true;

初始化-代码

然后是将我们的初始值放入矩阵中,因为我们初始值设定的是角度与速度大小,所以首先要把v给分解为xy轴上的。

%% 初始设置
time = 0:dt:time_end;
% 坐标
pos = zeros(N, 2, length(time));
pos(:,:,1) = pos0;
% 速度
vx = zeros(length(time), N);
vx(1,:) = v0.*cos(theta0);
vy = zeros(length(time), N);
vy(1,:) = v0.*sin(theta0);
% 加速度大小
a = zeros(length(time), N);

迭代开始

迭代的话这一步其实就和我们的逻辑很像了,不过之所以主代码这么简介,是因为我把一大堆复杂的内容全部放到了函数里面,只留个接口调用,这样子可以让主代码更加简洁明了。

%% 迭代开始
for t = 2:length(time)
    % 得到分加速度
    da = calAcceleration(pos(:,:,t-1));
    % 计算速度
    [vx(t,:), vy(t,:)] = calVelocity(vx(t-1,:), vy(t-1,:), da);
    % 计算位移
    pos(:,:,t) = calDisplacement(vx(t-1:t,:), vy(t-1:t,:), pos(:,:,t-1));
end

对于计算加速度的函数,主要的原理还是和上一篇讲的一样,通过万有引力公式求解,然后正交分解并叠加。

% 计算x与y轴加速度变化量da(3x2)
function da = calAcceleration(pos)
    global m;
    % 小球数量
    [n, ~] = size(pos);
    da = zeros(n, 2);
    for i = 1:n
        dax = 0;
        day = 0;
        for j = 1:n
            if i ~= j
                % i小球和j小球相对角度与距离
                [theta, r] = calRelatively(pos(i,:), pos(j,:));
                % 两个小球的引力大小
                F = calGravitation(r, i, j);
                % 第i个小球收到来自j的加速度分量
                dax = dax + F/m(i)*cos(theta);
                day = day + F/m(i)*sin(theta);
            end
        end
        da(i,:) = [dax, day];
    end
end

% 计算两个小球的相对角度与距离
function [theta, r] = calRelatively(pos1, pos2)
    dx = pos2(1) - pos1(1);
    dy = pos2(2) - pos1(2);
    r = sqrt(dx^2 + dy^2);
    theta = acos(dx/r);
    % 因为cos值的两个象限需要区分,所以这里要变换
    if dy < 0 && dx >0
        theta = -theta;
    end
    if dx < 0 && dy < 0
        theta = (pi-theta)+pi;
    end
end

% 计算两个小球引力大小
function F = calGravitation(r, i, j)
    global m G;
    F = G*m(i)*m(j)/r^2;
end

计算速度的函数,这个就很简单了,简单的速度与加速度公式。

% 计算小球的速度变化
function [vx, vy] = calVelocity(vx_p, vy_p, da)
    global dt;
    vx = vx_p + dt*da(:,1)';
    vy = vy_p + dt*da(:,2)';
end

计算当前坐标,方法同公式。

% 计算小球的位移变化
function pos = calDisplacement(vx, vy, pos_p)
    global dt;
    vx = vx';
    vy = vy';
    % 计算下一时刻的坐标
    pos(:,1) = pos_p(:,1) + (vx(:,1)+vx(:,2))/2*dt;
    pos(:,2) = pos_p(:,2) + (vy(:,1)+vy(:,2))/2*dt;
end

作图-代码

作图的话就没有这么简单了,因为还需要设置一大堆比较麻烦的图像参数。

对于做轨迹图,可以通过以下代码实现

% 做轨迹图像
plotPosition(pos, vx, vy, time)

% 做运动图像并保存视频
function plotPosition(pos, vx, vy, time)
    global isOutVideo;
    figure(1)
    if isOutVideo == true
        % 创建视频句柄,视频名称three_body.avi
        writerObj = VideoWriter('three_body.avi');
        open(writerObj);
        myMovie(1:length(time)) = struct('cdata', [], 'colormap', []);
    end
    % 迭代计算得到图像
    for t = 1:length(time)
        plotPosVec(pos(:,:,t), vx(t,:), vy(t,:), t, pos)
        if isOutVideo == true
            frame = getframe;
            % 修改帧参数
            frame.cdata = imresize(frame.cdata, [685, 685]);
            writeVideo(writerObj, frame);
        end
    end
    % 关闭视频句柄
    if isOutVideo == true
        close(writerObj);
    end
end

% 作图位置+速度矢量
function plotPosVec(pos, vx, vy, t, pos_all)
    % 小球
    global x_min x_max y_min y_max;
    figure(1)
    scatter(pos(:,1), pos(:,2), 'ok', 'filled')
    % 图像细节调整
    axis equal
    box on
    grid on
    set(gca, 'linewidth', 1.5, 'xtick', floor(linspace(x_min, x_max, 11)), 'ytick', floor(linspace(y_min, y_max, 11)))
    hold on
    % 三条速度线
    for i = 1:length(vx)
        line([pos(i,1) pos(i,1)+vx(i)/2], [pos(i,2), pos(i,2)+vy(i)/2], 'linewidth', 1.2)
    end
    % 添加轨道线
    plotCurrentTrace(pos_all, t)
    % 添加文本
    text(x_max*13/25, y_min*20/25, 'Made By Liang Hanpu', 'horiz', 'center', 'color', 'r')
    axis([x_min x_max y_min y_max])
    hold off
end

% 输出轨迹线
function plotCurrentTrace(pos, t)
    global x_min x_max y_min y_max;
    if t ~= 0
        [a, ~, ~] = size(pos);
        hold on
        axis equal
        box on
        grid on
        set(gca, 'linewidth', 1.5)
        axis([x_min x_max y_min y_max])
        for i = 1:a
            x = zeros(1, t);
            y = zeros(1, t);
            for j = 1:t
                x(j) = pos(i, 1, j);
                y(j) = pos(i, 2, j);
            end
            plot(x, y, 'linewidth', 1.5)
        end
    end
end

对于做时间随速度大小与角度的图像,可以由以下函数实现,这个就比较简单了。

% 做速度随时间图像
plotVelocity(vx, vy)

% 输出三个小球速度变化图与角度变化图
function plotVelocity(vx, vy)
    global dt time_end;    
    % 速度
    v = sqrt(vx.^2 + vy.^2);
    t = (0:dt:time_end)'*ones(1,3);
    % 角度
    theta = acos(vx./v);
    theta(vx>0&vy<0) = 2*pi-theta(vx>0&vy<0);
    theta(vx<0&vy<0) = (pi-theta(vx<0&vy<0))+pi;
    figure
    plot(t, v, 'linewidth', 1.2)
    box on
    xlabel('Time', 'fontsize', 16)
    ylabel('Velocity' , 'fontsize', 16)
    set(gca, 'linewidth', 1.2)
    figure
    plot(t,theta, 'linewidth', 1.2)
    xlabel('Time', 'fontsize', 16)
    ylabel('Angle \theta' , 'fontsize', 16)
    set(gca, 'linewidth', 1.2)
end

做出来的图形大概可以看成这样子,可以看出来还是有比较有趣的趋势的。

t-v
t-theta

最后

以上就是全部内容,我将会全部放在我的Github中,地址在文章开头有。

如果你学到了一些东西的话,麻烦点个赞,加个收藏来个关注噢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 如何写出三体的MATLAB程序-理论分析篇 写在前面 之所以写这个程序,是因为某天晚上无聊,室友正在学习MATLA...
    老梁家的风子阅读 2,182评论 0 2
  • [深入浅出多旋翼飞控开发][姿态篇][一][初识姿态估计] 作者:王伟韵QQ : 352707983Github ...
    梦萦蓝天阅读 22,493评论 0 12
  • 一、Unity简介 1. Unity界面 Shift + Space : 放大界面 Scene界面按钮渲染模式2D...
    MYves阅读 8,195评论 0 22
  • 今天工作上比较悠闲,没有太多的事。主要学习内容,是得到、量子学院、《刻意练习》。晚上看了插袋老师讲的关于创业的视频...
    则成思考888阅读 185评论 0 0
  • 看你开怀大笑 满目欢喜 我怎么可以过成现在的样子 你后悔现在才过成现在的样子 牵手走过的街 暖暖的情意 只求可以宁...
    海深处阅读 350评论 0 2