├── README.md ├── cal_function ├── calAcceleration.m ├── calDisplacement.m ├── calGravitation.m ├── calRelatively.m └── calVelocity.m ├── plot_function ├── plotCurrentTrace.m ├── plotPosVec.m ├── plotPosition.m └── plotVelocity.m ├── three_body.avi └── three_body_main.m /README.md: -------------------------------------------------------------------------------- 1 | # 三体MATLAB模拟 2 | 3 | ## 所需软件 4 | 5 | MATLAB较近版本。笔者本人用的是MATLAB R2018a。 6 | 7 | ## 编码 8 | 9 | 文件内所有中文编码为utf-8。用MATLAB打开时可能会出现乱码。 10 | 11 | ## 运行 12 | 13 | 打开three_body_main.m文件,运行即可。 14 | 15 | ## 简介 16 | 17 | 本程序用于模拟多个有质量质点在二维平面内受到万有引力运动的运动情况。 18 | 19 | - 初始条件: 坐标, 速度大小, 速度方向, 质量 20 | - 基础参数: 结束时间, 时间间隔, 万有引力系数, 输出图像边界大小, 是否输出图像 21 | - 输出文件: 该程序运行完毕后, 会在改文件夹下创建出three_body.avi视频文件 -------------------------------------------------------------------------------- /cal_function/calAcceleration.m: -------------------------------------------------------------------------------- 1 | % 计算x与y轴加速度变化量da(3x2) 2 | function da = calAcceleration(pos) 3 | global m; 4 | % 小球数量 5 | [n, ~] = size(pos); 6 | da = zeros(n, 2); 7 | for i = 1:n 8 | dax = 0; 9 | day = 0; 10 | for j = 1:n 11 | if i ~= j 12 | % i小球和j小球相对角度与距离 13 | [theta, r] = calRelatively(pos(i,:), pos(j,:)); 14 | % 两个小球的引力大小 15 | F = calGravitation(r, i, j); 16 | % 第i个小球收到来自j的加速度分量 17 | dax = dax + F/m(i)*cos(theta); 18 | day = day + F/m(i)*sin(theta); 19 | end 20 | end 21 | da(i,:) = [dax, day]; 22 | end 23 | end -------------------------------------------------------------------------------- /cal_function/calDisplacement.m: -------------------------------------------------------------------------------- 1 | % 计算小球的位移变化 2 | function pos = calDisplacement(vx, vy, pos_p) 3 | global dt; 4 | vx = vx'; 5 | vy = vy'; 6 | % 计算下一时刻的坐标 7 | pos(:,1) = pos_p(:,1) + (vx(:,1)+vx(:,2))/2*dt; 8 | pos(:,2) = pos_p(:,2) + (vy(:,1)+vy(:,2))/2*dt; 9 | end -------------------------------------------------------------------------------- /cal_function/calGravitation.m: -------------------------------------------------------------------------------- 1 | % 计算两个小球引力大小 2 | function F = calGravitation(r, i, j) 3 | global m G; 4 | F = G*m(i)*m(j)/r^2; 5 | end -------------------------------------------------------------------------------- /cal_function/calRelatively.m: -------------------------------------------------------------------------------- 1 | % 计算两个小球的相对角度与距离 2 | function [theta, r] = calRelatively(pos1, pos2) 3 | dx = pos2(1) - pos1(1); 4 | dy = pos2(2) - pos1(2); 5 | r = sqrt(dx^2 + dy^2); 6 | theta = acos(dx/r); 7 | % 因为cos值的两个象限需要区分,所以这里要变换 8 | if dy < 0 && dx >0 9 | theta = -theta; 10 | end 11 | if dx < 0 && dy < 0 12 | theta = (pi-theta)+pi; 13 | end 14 | end -------------------------------------------------------------------------------- /cal_function/calVelocity.m: -------------------------------------------------------------------------------- 1 | % 计算小球的速度变化 2 | function [vx, vy] = calVelocity(vx_p, vy_p, da) 3 | global dt; 4 | vx = vx_p + dt*da(:,1)'; 5 | vy = vy_p + dt*da(:,2)'; 6 | end -------------------------------------------------------------------------------- /plot_function/plotCurrentTrace.m: -------------------------------------------------------------------------------- 1 | % 绘制轨迹 2 | function plotCurrentTrace(pos, t) 3 | global x_min x_max y_min y_max; 4 | if t ~= 0 5 | [a, ~, ~] = size(pos); 6 | hold on 7 | axis equal 8 | box on 9 | grid on 10 | set(gca, 'linewidth', 1.5) 11 | axis([x_min x_max y_min y_max]) 12 | for i = 1:a 13 | x = zeros(1, t); 14 | y = zeros(1, t); 15 | for j = 1:t 16 | x(j) = pos(i, 1, j); 17 | y(j) = pos(i, 2, j); 18 | end 19 | plot(x, y, 'linewidth', 1.5) 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /plot_function/plotPosVec.m: -------------------------------------------------------------------------------- 1 | % 作图位置+速度矢量 2 | function plotPosVec(pos, vx, vy, t, pos_all) 3 | % 小球 4 | global x_min x_max y_min y_max; 5 | figure(1) 6 | scatter(pos(:,1), pos(:,2), 'ok', 'filled') 7 | % 图像细节调整 8 | axis equal 9 | box on 10 | grid on 11 | set(gca, 'linewidth', 1.5, 'xtick', floor(linspace(x_min, x_max, 11)), 'ytick', floor(linspace(y_min, y_max, 11))) 12 | hold on 13 | % 三条速度线 14 | for i = 1:length(vx) 15 | line([pos(i,1) pos(i,1)+vx(i)/2], [pos(i,2), pos(i,2)+vy(i)/2], 'linewidth', 1.2) 16 | end 17 | % 添加轨道线 18 | plotCurrentTrace(pos_all, t) 19 | % 添加文本 20 | text(x_max*13/25, y_min*20/25, 'Made By Liang Hanpu', 'horiz', 'center', 'color', 'r') 21 | axis([x_min x_max y_min y_max]) 22 | hold off 23 | end -------------------------------------------------------------------------------- /plot_function/plotPosition.m: -------------------------------------------------------------------------------- 1 | % 做运动图像并保存视频 2 | function plotPosition(pos, vx, vy, time) 3 | global isOutVideo; 4 | figure(1) 5 | if isOutVideo == true 6 | % 创建视频句柄,视频名称three_body.avi 7 | writerObj = VideoWriter('three_body.avi'); 8 | open(writerObj); 9 | myMovie(1:length(time)) = struct('cdata', [], 'colormap', []); 10 | end 11 | % 迭代计算得到图像 12 | for t = 1:length(time) 13 | plotPosVec(pos(:,:,t), vx(t,:), vy(t,:), t, pos) 14 | if isOutVideo == true 15 | frame = getframe; 16 | % 修改帧参数 17 | frame.cdata = imresize(frame.cdata, [685, 685]); 18 | writeVideo(writerObj, frame); 19 | end 20 | end 21 | % 关闭视频句柄 22 | if isOutVideo == true 23 | close(writerObj); 24 | end 25 | end -------------------------------------------------------------------------------- /plot_function/plotVelocity.m: -------------------------------------------------------------------------------- 1 | % 输出三个小球速度变化图与角度变化图 2 | function plotVelocity(vx, vy) 3 | global dt time_end; 4 | % 速度 5 | v = sqrt(vx.^2 + vy.^2); 6 | t = (0:dt:time_end)'*ones(1,3); 7 | % 角度 8 | theta = acos(vx./v); 9 | theta(vx>0&vy<0) = 2*pi-theta(vx>0&vy<0); 10 | theta(vx<0&vy<0) = (pi-theta(vx<0&vy<0))+pi; 11 | figure 12 | plot(t, v, 'linewidth', 1.2) 13 | box on 14 | xlabel('Time', 'fontsize', 16) 15 | ylabel('Velocity' , 'fontsize', 16) 16 | set(gca, 'linewidth', 1.2) 17 | figure 18 | plot(t,theta, 'linewidth', 1.2) 19 | xlabel('Time', 'fontsize', 16) 20 | ylabel('Angle \theta' , 'fontsize', 16) 21 | set(gca, 'linewidth', 1.2) 22 | end -------------------------------------------------------------------------------- /three_body.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HanpuLiang/Three-Body-by-MATLAB/cc43aed964a3b72adabf9091c7ace4c2556d843e/three_body.avi -------------------------------------------------------------------------------- /three_body_main.m: -------------------------------------------------------------------------------- 1 | clc, clear, close all 2 | 3 | %{ 4 | 个人声明: 5 | @author: Liang Hanpu 6 | @bilibili ID: 小风寒呐 7 | @date: 2019/3/3 8 | @description: 本程序用于模拟多个有质量质点在二维平面内受到万有引力运动的运动情况。 9 | 初始条件: 坐标, 速度大小, 速度方向, 质量 10 | 基础参数: 结束时间, 时间间隔, 万有引力系数, 输出图像边界大小 11 | 输出文件: 该程序运行完毕后, 会在改文件夹下创建出three_body.avi视频文件 12 | @statement: 此程序修改, 转发时请注明原作者。 13 | %} 14 | 15 | %% 初始条件 16 | addpath(genpath('./plot_function')) 17 | addpath(genpath('./cal_function')) 18 | % 初始条件为以圆心为(0, 0)半径r的圆上有三个等质量的点 19 | r = 10; 20 | % 坐标(等边三角形) 21 | pos0 = [0, r; r/2*sqrt(3), -r/2; -r/2*sqrt(3), -r/2]; 22 | % 速度大小 23 | v0 = [6, 6, 6]; 24 | % 速度方向(x轴正方向为参考) 25 | theta0 = [0, 4*pi/3, 2*pi/3]; 26 | 27 | %% 参数设置 28 | global G dt m x_min x_max y_min y_max time_end isOutVideo; 29 | % 结束时间 30 | time_end = 10; 31 | % 时间间隔 32 | dt = 0.05; 33 | % 万有引力系数,随便设置的 34 | G = 1; 35 | % 质量 36 | m = [1000, 1000, 1000]; 37 | % 小球个数 38 | N = length(v0); 39 | % 图像边界 40 | x_min = -25; 41 | x_max = -x_min; 42 | y_min = x_min; 43 | y_max = -y_min; 44 | % 是否输出视频图像 45 | isOutVideo = true; 46 | 47 | %% 初始设置 48 | time = 0:dt:time_end; 49 | % 坐标 50 | pos = zeros(N, 2, length(time)); 51 | pos(:,:,1) = pos0; 52 | % 速度 53 | vx = zeros(length(time), N); 54 | vx(1,:) = v0.*cos(theta0); 55 | vy = zeros(length(time), N); 56 | vy(1,:) = v0.*sin(theta0); 57 | % 加速度大小 58 | a = zeros(length(time), N); 59 | 60 | %% 迭代开始 61 | for t = 2:length(time) 62 | % 得到分加速度 63 | da = calAcceleration(pos(:,:,t-1)); 64 | % 计算速度 65 | [vx(t,:), vy(t,:)] = calVelocity(vx(t-1,:), vy(t-1,:), da); 66 | % 计算位移 67 | pos(:,:,t) = calDisplacement(vx(t-1:t,:), vy(t-1:t,:), pos(:,:,t-1)); 68 | end 69 | 70 | %% 作图区 71 | % 做轨迹图像 72 | plotPosition(pos, vx, vy, time) 73 | % 做速度随时间图像 74 | plotVelocity(vx, vy) --------------------------------------------------------------------------------