三体问题详解

news2025/6/12 16:23:18

从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解析解。

🧭 问题设定:三体系统的基本假设

假设我们有三个质量分别为 m 1 , m 2 , m 3 m_1, m_2, m_3 m1,m2,m3 的天体,位置向量分别为:

  • r 1 ( t ) \mathbf{r}_1(t) r1(t)
  • r 2 ( t ) \mathbf{r}_2(t) r2(t)
  • r 3 ( t ) \mathbf{r}_3(t) r3(t)

在牛顿引力定律下,每个天体受到其余两个天体的引力,总加速度由牛顿第二定律( F = m a \mathbf{F} = m\mathbf{a} F=ma)给出。


📐 一般形式的运动方程(牛顿引力 + 牛顿第二定律)

对第一个天体 m 1 m_1 m1,其加速度为:

m 1 d 2 r 1 d t 2 = G m 1 m 2 ∣ r 2 − r 1 ∣ 3 ( r 2 − r 1 ) + G m 1 m 3 ∣ r 3 − r 1 ∣ 3 ( r 3 − r 1 ) m_1 \frac{d^2 \mathbf{r}_1}{dt^2} = G \frac{m_1 m_2}{|\mathbf{r}_2 - \mathbf{r}_1|^3} (\mathbf{r}_2 - \mathbf{r}_1) + G \frac{m_1 m_3}{|\mathbf{r}_3 - \mathbf{r}_1|^3} (\mathbf{r}_3 - \mathbf{r}_1) m1dt2d2r1=Gr2r13m1m2(r2r1)+Gr3r13m1m3(r3r1)

类似地,对 m 2 , m 3 m_2, m_3 m2,m3 分别有:

m 2 d 2 r 2 d t 2 = G m 2 m 1 ∣ r 1 − r 2 ∣ 3 ( r 1 − r 2 ) + G m 2 m 3 ∣ r 3 − r 2 ∣ 3 ( r 3 − r 2 ) m_2 \frac{d^2 \mathbf{r}_2}{dt^2} = G \frac{m_2 m_1}{|\mathbf{r}_1 - \mathbf{r}_2|^3} (\mathbf{r}_1 - \mathbf{r}_2) + G \frac{m_2 m_3}{|\mathbf{r}_3 - \mathbf{r}_2|^3} (\mathbf{r}_3 - \mathbf{r}_2) m2dt2d2r2=Gr1r23m2m1(r1r2)+Gr3r23m2m3(r3r2)

m 3 d 2 r 3 d t 2 = G m 3 m 1 ∣ r 1 − r 3 ∣ 3 ( r 1 − r 3 ) + G m 3 m 2 ∣ r 2 − r 3 ∣ 3 ( r 2 − r 3 ) m_3 \frac{d^2 \mathbf{r}_3}{dt^2} = G \frac{m_3 m_1}{|\mathbf{r}_1 - \mathbf{r}_3|^3} (\mathbf{r}_1 - \mathbf{r}_3) + G \frac{m_3 m_2}{|\mathbf{r}_2 - \mathbf{r}_3|^3} (\mathbf{r}_2 - \mathbf{r}_3) m3dt2d2r3=Gr1r33m3m1(r1r3)+Gr2r33m3m2(r2r3)


⚠️ 为什么不稳定?

1. 非线性耦合微分方程组

这三组式子彼此高度耦合:每个加速度都依赖于另外两个天体的位置,而且这种依赖是非线性(距离的三次方在分母)。

这是典型的非线性二阶常微分方程组,形式上如下:

d 2 r i d t 2 = ∑ j ≠ i G m j r j − r i ∣ r j − r i ∣ 3 , i = 1 , 2 , 3 \frac{d^2 \mathbf{r}_i}{dt^2} = \sum_{j \ne i} G m_j \frac{\mathbf{r}_j - \mathbf{r}_i}{|\mathbf{r}_j - \mathbf{r}_i|^3}, \quad i = 1,2,3 dt2d2ri=j=iGmjrjri3rjri,i=1,2,3

这种系统存在如下三大特性:

  • 不可分解成单体运动 + 微扰项
  • 无法通过代数方法求出通解
  • 随时间演化会展现出对初始条件的极度敏感

2. 初始条件敏感性(混沌特征)

在数值模拟中,即使两个三体系统初始位置差异为 10 − 10 10^{-10} 1010 米,几十个周期后轨道会完全不同。

这是混沌系统的定义特征:

初始条件微小扰动会被放大,导致长期行为完全不可预测。


3. 守恒定律约束不足以稳定系统

虽然系统满足以下守恒定律:

  • 总动量守恒:

    ∑ i = 1 3 m i d r i d t = 常量 \sum_{i=1}^3 m_i \frac{d \mathbf{r}_i}{dt} = \text{常量} i=13midtdri=常量

  • 总能量守恒:

    E = ∑ i = 1 3 1 2 m i v i 2 − ∑ i < j G m i m j ∣ r i − r j ∣ E = \sum_{i=1}^3 \frac{1}{2} m_i v_i^2 - \sum_{i<j} \frac{G m_i m_j}{|\mathbf{r}_i - \mathbf{r}_j|} E=i=1321mivi2i<jrirjGmimj

但这些守恒量(常数)无法限制轨道在高维空间的发散演化,只是提供一些“整体约束”。

📉 所以为什么不能稳定运行?

从物理角度总结三点:

  1. 多体引力是非线性且时变的力学系统;
  2. 无解析解(除极少对称情况),必须数值求解;
  3. 即使数值解,也极度依赖初始条件,最终表现为混沌轨道;

🎯 实际结果是什么?

小说中三体行星文明面临的核心困境——无法预测三颗恒星的运动。正是这个真实的物理问题,使得三体文明的“乱纪元”和“恒纪元”交替成为必然,也解释了为什么他们需要寻找新的家园。数值模拟证实了这种不稳定性是三体系统的内在属性,而非外部干扰的结果。

三体运动的模拟动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib.patches as patches
from matplotlib.widgets import Button
from collections import deque

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False


class ThreeBodySystem:
    def __init__(self, masses, positions, velocities, G=1.0):
        """
        三体系统
        masses: [m1, m2, m3] 三个天体的质量
        positions: [[x1,y1], [x2,y2], [x3,y3]] 初始位置
        velocities: [[vx1,vy1], [vx2,vy2], [vx3,vy3]] 初始速度
        G: 引力常数
        """
        self.masses = np.array(masses)
        self.positions = np.array(positions, dtype=float)
        self.velocities = np.array(velocities, dtype=float)
        self.G = G

        # 轨迹历史记录 - 为每个天体单独记录
        self.trail_length = 800
        self.trails = [deque(maxlen=self.trail_length) for _ in range(3)]

        # 初始化轨迹记录
        for i in range(3):
            self.trails[i].append([self.positions[i][0], self.positions[i][1]])

        self.dt = 0.005  # 基础时间步长
        self.speed_multiplier = 1.0  # 速度倍数
        self.time = 0

        # 天体属性
        self.colors = ['#FF6B35', '#004E89', '#00A86B']  # 橙色、深蓝、绿色
        self.names = ['恒星Alpha', '恒星Beta', '恒星Gamma']
        self.base_sizes = [300, 250, 280]

        # 统计数据记录
        self.energy_history = deque(maxlen=500)
        self.distance_history = {'AB': deque(maxlen=500),
                                 'AC': deque(maxlen=500),
                                 'BC': deque(maxlen=500)}

    def set_speed_multiplier(self, multiplier):
        """设置速度倍数"""
        self.speed_multiplier = max(0.1, min(10.0, multiplier))

    def compute_gravitational_forces(self):
        """计算每个天体受到的引力"""
        forces = np.zeros_like(self.positions)

        for i in range(3):
            for j in range(3):
                if i != j:
                    # 位置差矢量: 从i指向j
                    r_vec = self.positions[j] - self.positions[i]
                    r_magnitude = np.linalg.norm(r_vec)

                    # 避免数值奇点
                    if r_magnitude > 1e-8:
                        # 万有引力: F = G*m1*m2/r^2 * 单位矢量
                        force_magnitude = self.G * self.masses[i] * self.masses[j] / (r_magnitude ** 3)
                        forces[i] += force_magnitude * r_vec

        return forces

    def runge_kutta_4th_order(self):
        """四阶龙格-库塔法数值积分(带速度控制)"""
        effective_dt = self.dt * self.speed_multiplier

        # 当前状态
        pos = self.positions.copy()
        vel = self.velocities.copy()

        # k1 计算
        k1_vel = vel
        k1_acc = self.compute_gravitational_forces() / self.masses.reshape(-1, 1)

        # k2 计算
        pos_k2 = pos + 0.5 * effective_dt * k1_vel
        self.positions = pos_k2  # 临时更新位置用于力计算
        k2_vel = vel + 0.5 * effective_dt * k1_acc
        k2_acc = self.compute_gravitational_forces() / self.masses.reshape(-1, 1)

        # k3 计算
        pos_k3 = pos + 0.5 * effective_dt * k2_vel
        self.positions = pos_k3
        k3_vel = vel + 0.5 * effective_dt * k2_acc
        k3_acc = self.compute_gravitational_forces() / self.masses.reshape(-1, 1)

        # k4 计算
        pos_k4 = pos + effective_dt * k3_vel
        self.positions = pos_k4
        k4_vel = vel + effective_dt * k3_acc
        k4_acc = self.compute_gravitational_forces() / self.masses.reshape(-1, 1)

        # 最终更新
        self.positions = pos + effective_dt * (k1_vel + 2 * k2_vel + 2 * k3_vel + k4_vel) / 6
        self.velocities = vel + effective_dt * (k1_acc + 2 * k2_acc + 2 * k3_acc + k4_acc) / 6

        # 记录轨迹
        for i in range(3):
            self.trails[i].append([self.positions[i][0], self.positions[i][1]])

        self.time += effective_dt

    def calculate_total_energy(self):
        """计算系统总能量(动能+势能)"""
        # 动能
        kinetic_energy = 0
        for i in range(3):
            v_squared = np.sum(self.velocities[i] ** 2)
            kinetic_energy += 0.5 * self.masses[i] * v_squared

        # 引力势能
        potential_energy = 0
        for i in range(3):
            for j in range(i + 1, 3):
                r = np.linalg.norm(self.positions[i] - self.positions[j])
                if r > 1e-8:
                    potential_energy -= self.G * self.masses[i] * self.masses[j] / r

        return kinetic_energy + potential_energy

    def update_statistics(self):
        """更新统计数据"""
        # 总能量
        energy = self.calculate_total_energy()
        self.energy_history.append(energy)

        # 天体间距离
        r_AB = np.linalg.norm(self.positions[0] - self.positions[1])
        r_AC = np.linalg.norm(self.positions[0] - self.positions[2])
        r_BC = np.linalg.norm(self.positions[1] - self.positions[2])

        self.distance_history['AB'].append(r_AB)
        self.distance_history['AC'].append(r_AC)
        self.distance_history['BC'].append(r_BC)


class SpeedController:
    """速度控制器类"""

    def __init__(self, system):
        self.system = system
        self.speed_levels = [0.1, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0]
        self.current_level = 3  # 默认1.0倍速

    def speed_up(self, event=None):
        """加速"""
        if self.current_level < len(self.speed_levels) - 1:
            self.current_level += 1
            self.current_level = min(self.current_level, len(self.speed_levels)-1)
            self.system.set_speed_multiplier(self.speed_levels[self.current_level])

    def slow_down(self, event=None):
        """减速"""
        if self.current_level > 0:
            self.current_level -= 1
            self.current_level = max(self.current_level, 0)
            self.system.set_speed_multiplier(self.speed_levels[self.current_level])

    def reset_speed(self, event=None):
        """重置到正常速度"""
        self.current_level = 3
        self.system.set_speed_multiplier(self.speed_levels[self.current_level])

    def get_current_speed_text(self):
        """获取当前速度显示文本"""
        speed = self.speed_levels[self.current_level]
        return f"播放速度: {speed:.1f}x"


def create_three_body_animation():
    """创建带速度控制的三体运动动画"""

    # 初始化系统 - 选择一个展现混沌特性的配置
    masses = [1.5, 1.0, 1.2]  # 三个不同质量的恒星

    # 三角形初始配置,但有适当的速度产生复杂轨道
    positions = [
        [-2.0, 0.0],  # Alpha星
        [1.0, 1.732],  # Beta星
        [1.0, -1.732]  # Gamma星
    ]

    velocities = [
        [0.2, 0.8],  # Alpha星初始速度
        [-0.6, -0.2],  # Beta星初始速度
        [0.4, -0.6]  # Gamma星初始速度
    ]

    system = ThreeBodySystem(masses, positions, velocities, G=3.0)
    speed_controller = SpeedController(system)

    # 创建图形界面
    fig = plt.figure(figsize=(19, 12), facecolor='#0a0a0a')

    # 主动画区域 (左侧大图)
    ax_main = plt.subplot2grid((3, 5), (0, 0), colspan=3, rowspan=3, facecolor='#0a0a0a')

    # 监控面板 (右侧)
    ax_energy = plt.subplot2grid((3, 5), (0, 3), colspan=2, facecolor='#0a0a0a')
    ax_distances = plt.subplot2grid((3, 5), (1, 3), colspan=2, facecolor='#0a0a0a')
    ax_info = plt.subplot2grid((3, 5), (2, 3), colspan=2, facecolor='#0a0a0a')

    # 在底部为按钮留出空间
    plt.subplots_adjust(bottom=0.15)

    # 创建速度控制按钮
    button_height = 0.04
    button_width = 0.08
    button_y = 0.02

    # 减速按钮
    ax_slow = plt.axes([0.25, button_y, button_width, button_height])
    btn_slow = Button(ax_slow, '减速', color='#FF4444', hovercolor='#FF6666')
    btn_slow.label.set_color('white')
    btn_slow.label.set_fontweight('bold')

    # 重置按钮
    ax_reset = plt.axes([0.35, button_y, button_width, button_height])
    btn_reset = Button(ax_reset, '正常', color='#4CAF50', hovercolor='#6BCF7F')
    btn_reset.label.set_color('white')
    btn_reset.label.set_fontweight('bold')

    # 加速按钮
    ax_fast = plt.axes([0.45, button_y, button_width, button_height])
    btn_fast = Button(ax_fast, '加速', color='#2196F3', hovercolor='#42A5F5')
    btn_fast.label.set_color('white')
    btn_fast.label.set_fontweight('bold')

    # 暂停/继续按钮
    ax_pause = plt.axes([0.55, button_y, button_width, button_height])
    btn_pause = Button(ax_pause, '暂停', color='#FF9800', hovercolor='#FFB74D')
    btn_pause.label.set_color('white')
    btn_pause.label.set_fontweight('bold')

    # 速度显示文本
    speed_text = fig.text(0.65, button_y + button_height / 2,
                          speed_controller.get_current_speed_text(),
                          fontsize=12, color='white', va='center', weight='bold')

    # 设置主画布
    ax_main.set_xlim(-8, 8)
    ax_main.set_ylim(-8, 8)
    ax_main.set_aspect('equal')
    ax_main.set_facecolor('#0a0a0a')
    ax_main.tick_params(colors='white')
    ax_main.set_xlabel('X 坐标', color='white', fontsize=14)
    ax_main.set_ylabel('Y 坐标', color='white', fontsize=14)
    ax_main.set_title('三体问题:三颗恒星的混沌舞蹈', color='white', fontsize=16, pad=20)

    # 创建星空背景
    np.random.seed(123)
    star_x = np.random.uniform(-8, 8, 200)
    star_y = np.random.uniform(-8, 8, 200)
    star_sizes = np.random.uniform(0.5, 3, 200)
    ax_main.scatter(star_x, star_y, c='white', s=star_sizes, alpha=0.4)

    # 添加网格
    ax_main.grid(True, alpha=0.15, color='gray', linestyle='-', linewidth=0.5)

    # 初始化绘图元素
    # 1. 三个恒星天体
    stars = []
    for i in range(3):
        star = ax_main.scatter([], [], s=system.base_sizes[i],
                               c=system.colors[i], edgecolors='white',
                               linewidth=3, alpha=0.95, zorder=20)
        stars.append(star)

    # 2. 三条轨迹线
    orbit_trails = []
    for i in range(3):
        trail, = ax_main.plot([], [], color=system.colors[i],
                              linewidth=2.5, alpha=0.8, zorder=10)
        orbit_trails.append(trail)

    # 3. 引力连接线
    gravity_lines = []
    gravity_colors = ['yellow', 'orange', 'red']
    line_pairs = [(0, 1), (0, 2), (1, 2)]

    for i, (a, b) in enumerate(line_pairs):
        line, = ax_main.plot([], [], color=gravity_colors[i],
                             alpha=0.4, linewidth=2, linestyle='--', zorder=5)
        gravity_lines.append(line)

    # 4. 恒星标签
    star_labels = []
    for i in range(3):
        label = ax_main.text(0, 0, system.names[i], fontsize=12, color='white',
                             ha='center', va='center', weight='bold',
                             bbox=dict(boxstyle="round,pad=0.3", facecolor=system.colors[i], alpha=0.7))
        star_labels.append(label)

    # 5. 信息显示
    status_text = ax_main.text(0.02, 0.98, '', transform=ax_main.transAxes,
                               fontsize=12, color='white', verticalalignment='top',
                               bbox=dict(boxstyle="round,pad=0.5",
                                         facecolor="black", alpha=0.8))

    # 设置监控图表
    for ax in [ax_energy, ax_distances]:
        ax.set_facecolor('#0a0a0a')
        ax.tick_params(colors='white')
        ax.grid(True, alpha=0.3, color='gray')

    # 能量图
    ax_energy.set_title('系统总能量守恒', color='white', fontsize=12)
    ax_energy.set_ylabel('总能量', color='white')
    energy_line, = ax_energy.plot([], [], color='cyan', linewidth=2)

    # 距离图
    ax_distances.set_title('恒星间距离变化', color='white', fontsize=12)
    ax_distances.set_ylabel('距离', color='white')
    ax_distances.set_xlabel('时间步', color='white')

    dist_lines = {}
    dist_colors = ['red', 'blue', 'green']
    dist_labels = ['Alpha-Beta', 'Alpha-Gamma', 'Beta-Gamma']

    for i, key in enumerate(['AB', 'AC', 'BC']):
        line, = ax_distances.plot([], [], color=dist_colors[i],
                                  linewidth=2, label=dist_labels[i])
        dist_lines[key] = line
    ax_distances.legend(fontsize=10)

    # 信息面板
    ax_info.set_facecolor('#0a0a0a')
    ax_info.axis('off')
    info_display = ax_info.text(0.05, 0.95, '', transform=ax_info.transAxes,
                                fontsize=11, color='white', verticalalignment='top')

    # 动画状态控制
    animation_paused = [False]  # 使用列表以便在闭包中修改

    def toggle_pause(event):
        """切换暂停/继续"""
        animation_paused[0] = not animation_paused[0]
        btn_pause.label.set_text('继续' if animation_paused[0] else '暂停')

    def update_speed_display():
        """更新速度显示"""
        speed_text.set_text(speed_controller.get_current_speed_text())
        fig.canvas.draw_idle()

    def on_speed_up(event):
        speed_controller.speed_up()
        update_speed_display()

    def on_slow_down(event):
        speed_controller.slow_down()
        update_speed_display()

    def on_reset_speed(event):
        speed_controller.reset_speed()
        update_speed_display()

    # 连接按钮事件
    btn_fast.on_clicked(on_speed_up)
    btn_slow.on_clicked(on_slow_down)
    btn_reset.on_clicked(on_reset_speed)
    btn_pause.on_clicked(toggle_pause)

    def animate_frame(frame):
        # 如果暂停则不更新
        if animation_paused[0]:
            return (stars + orbit_trails + gravity_lines + star_labels +
                    [status_text, energy_line] + list(dist_lines.values()) + [info_display])

        # 执行物理计算 - 每帧多步提高精度
        steps_per_frame = max(1, int(3 / max(0.1, system.speed_multiplier)))
        for _ in range(steps_per_frame):
            system.runge_kutta_4th_order()
            system.update_statistics()

        # 更新三个恒星的位置
        for i in range(3):
            # 更新恒星位置
            current_pos = system.positions[i].reshape(1, -1)
            stars[i].set_offsets(current_pos)

            # 添加脉动效果
            pulse = 1 + 0.2 * np.sin(system.time * 4 + i * 2)
            stars[i].set_sizes([system.base_sizes[i] * pulse])

            # 更新标签位置
            star_labels[i].set_position((system.positions[i][0] + 0.5,
                                         system.positions[i][1] + 0.5))

        # 更新轨迹
        for i in range(3):
            if len(system.trails[i]) > 1:
                trail_array = np.array(list(system.trails[i]))
                orbit_trails[i].set_data(trail_array[:, 0], trail_array[:, 1])

        # 更新引力连接线
        for i, (a, b) in enumerate(line_pairs):
            pos_a = system.positions[a]
            pos_b = system.positions[b]
            gravity_lines[i].set_data([pos_a[0], pos_b[0]], [pos_a[1], pos_b[1]])

            # 根据距离调整线条粗细和透明度
            distance = np.linalg.norm(pos_a - pos_b)
            alpha = max(0.2, min(0.8, 5.0 / distance))
            linewidth = max(1, min(4, 8.0 / distance))
            gravity_lines[i].set_alpha(alpha)
            gravity_lines[i].set_linewidth(linewidth)

        # 更新状态信息
        current_energy = system.calculate_total_energy()
        max_velocity = max([np.linalg.norm(v) for v in system.velocities])

        status_info = (
            f"模拟时间: {system.time:.2f}\n"
            f"播放速度: {system.speed_multiplier:.1f}x\n"
            f"系统总能量: {current_energy:.4f}\n"
            f"最大速度: {max_velocity:.3f}\n"
            f"计算步数: {frame * steps_per_frame}\n"
            f"\n三体位置坐标:\n"
        )

        for i in range(3):
            pos = system.positions[i]
            vel_mag = np.linalg.norm(system.velocities[i])
            status_info += f"{system.names[i]}: ({pos[0]:.2f}, {pos[1]:.2f})\n"
            status_info += f"   速度: {vel_mag:.3f}\n"

        status_text.set_text(status_info)

        # 更新能量图
        if len(system.energy_history) > 1:
            time_points = list(range(len(system.energy_history)))
            energy_line.set_data(time_points, list(system.energy_history))
            ax_energy.relim()
            ax_energy.autoscale_view()

        # 更新距离图
        if len(system.distance_history['AB']) > 1:
            time_points = list(range(len(system.distance_history['AB'])))
            for key in ['AB', 'AC', 'BC']:
                dist_lines[key].set_data(time_points, list(system.distance_history[key]))
            ax_distances.relim()
            ax_distances.autoscale_view()

        # 更新信息面板
        min_dist = min([list(system.distance_history[key])[-1]
                        for key in system.distance_history.keys()
                        if len(system.distance_history[key]) > 0])

        info_text = (
            "=== 三体系统状态 ===\n\n"
            f"恒星质量:\n"
            f"  {system.names[0]}: {system.masses[0]:.1f}M☉\n"
            f"  {system.names[1]}: {system.masses[1]:.1f}M☉\n"
            f"  {system.names[2]}: {system.masses[2]:.1f}M☉\n\n"
            f"最近距离: {min_dist:.3f}\n"
            f"引力常数: {system.G:.1f}\n\n"
            "观察要点:\n"
            "*  轨道的不规则性\n"
            "*  近距离遭遇事件\n"
            "*  能量守恒定律\n"
            "*  混沌敏感依赖性\n\n"
            "控制说明:\n"
            "*  加速/减速按钮调节播放速度\n"
            "*  暂停按钮停止/继续动画\n"
            "*  正常按钮重置为1x速度"
        )

        info_display.set_text(info_text)

        return (stars + orbit_trails + gravity_lines + star_labels +
                [status_text, energy_line] + list(dist_lines.values()) + [info_display])

    # 创建动画对象
    anim = FuncAnimation(fig, animate_frame, frames=3000,
                         interval=30, blit=False, repeat=True, cache_frame_data=False)

    # 总标题
    fig.suptitle('三体问题数值模拟:混沌引力系统(速度可控)',
                 fontsize=18, color='white', y=0.96)

    # 底部说明
    fig.text(0.02, 0.085,
             '物理原理: 三个质量不等的恒星在万有引力作用下的非周期运动 | '
             '混沌特征: 轨道不可预测、对初始条件敏感、长期行为无法确定 | '
             '数值方法: 四阶龙格-库塔法求解牛顿引力方程组',
             fontsize=10, color='white',
             bbox=dict(boxstyle="round,pad=0.5", facecolor="#1a1a2e", alpha=0.9))

    plt.tight_layout()
    plt.subplots_adjust(top=0.92, bottom=0.18)
    plt.show()

    return anim


# 启动三体动画
print("🌟 启动三体恒星系统动态模拟(带速度控制)...")
print("\n系统配置:")
print("*  三颗质量不等的恒星: Alpha(1.5M☉), Beta(1.0M☉), Gamma(1.2M☉)")
print("*  初始三角形配置,赋予复杂初始速度")
print("*  高精度数值积分(RK4)确保长期稳定性")

print("\n可视化特征:")
print("✓ 三个不同颜色的恒星实时运动")
print("✓ 彩色轨迹显示历史路径")
print("✓ 虚线显示引力相互作用")
print("✓ 恒星大小脉动模拟真实效果")
print("✓ 实时监控能量守恒和距离变化")

print("\n新增速度控制功能:")
print("🎮 减速按钮: 降低播放速度(0.1x-8x)")
print("🎮 加速按钮: 提高播放速度(0.1x-8x)")
print("🎮 正常按钮: 重置为1x正常速度")
print("🎮 暂停按钮: 暂停/继续动画播放")
print("🎮 实时速度显示: 当前播放倍数")

print("\n观察重点:")
print("🔍 轨道的复杂性和不可预测性")
print("🔍 恒星间距离的剧烈变化")
print("🔍 近距离遭遇引起的轨道突变")
print("🔍 系统总能量的精确守恒")

print("\n操作提示:")
print("💡 使用加速功能快速观察长期行为")
print("💡 使用减速功能仔细研究细节变化")
print("💡 暂停功能方便截图和观察")

print("\n正在加载动画...")

# 运行动画
animation = create_three_body_animation()

print("🎬 三体动画已启动!使用底部按钮控制播放速度...")
___

参考

  • 三体问题究竟是什么?为什么说科学的尽头是神学?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2407579.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…