极限思想可视化

芝诺悖论

围绕芝诺悖论,观察芝诺悖论、无穷级数、数列收敛之间的关系与推理路径。

打开原视频

zeno_paradox.py
1# -*- coding: utf-8 -*-2from manim import *3import numpy as np4 5class ZenoParadox(Scene):6    def construct(self):7        # 设置默认字体8        Text.set_default(font="SimSun")9        10        # 标题11        title = Text("芝诺悖论:阿基里斯追乌龟").scale(0.8)12        title.to_edge(UP, buff=0.5)13        self.play(Write(title))14        self.wait(1)15 16        # 初始条件说明17        conditions = VGroup(18            Text("初始条件:").scale(0.6),19            VGroup(20                Text("速度:", color=RED).scale(0.4),21                MathTex("v_A = 2").scale(0.5)22            ).arrange(RIGHT, buff=0.2),23            VGroup(24                Text("速度:", color=GREEN).scale(0.4),25                MathTex("v_T = 1").scale(0.5)26            ).arrange(RIGHT, buff=0.2)27        ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)28        conditions.next_to(title, DOWN, buff=0.5)29        30        self.play(Write(conditions))31        self.wait(2)32 33        # 创建数轴34        number_line = NumberLine(35            x_range=[0, 5, 1],  # 范围改为0到536            length=12,          # 调整长度37            include_numbers=True,38            include_tip=True39        )40        number_line.shift(DOWN)41 42        # 创建角色43        achilles = Text("A", color=RED).scale(0.6)44        turtle = Text("T", color=GREEN).scale(0.6)45        46        # 设置初始位置47        achilles.move_to(number_line.number_to_point(0) + UP * 0.5)48        turtle.move_to(number_line.number_to_point(2) + UP * 0.5)49        50        # 修改初始位置标注,添加时间51        initial_brace = Brace(52            Line(53                number_line.number_to_point(0),54                number_line.number_to_point(2)55            ),56            UP57        )58        initial_labels = VGroup(59            MathTex("s_1 = 2").scale(0.4),60            MathTex("t_1 = 1").scale(0.4)  # 添加时间标注61        ).arrange(DOWN, buff=0.1)62        initial_labels.next_to(initial_brace, UP, buff=0.1)63        64        self.play(65            Create(number_line),66            FadeIn(achilles),67            FadeIn(turtle),68            Create(initial_brace),69            Write(initial_labels)70        )71 72        # 修改追赶过程的路程和时间定义73        steps = [74            {"s": 2, "t": 1},           # s₁=2 (第一段2米,用1秒)75            {"s": 1, "t": r"\frac{1}{2}"},     # s₂=1 (第二段1米,用0.5秒)76            {"s": r"\frac{1}{2}", "t": r"\frac{1}{4}"},   # s₃=1/2 (第三段0.5米,用0.25秒)77            {"s": r"\frac{1}{4}", "t": r"\frac{1}{8}"}    # s₄=1/4 (第四段0.25米,用0.125秒)78        ]79        80        braces_and_labels = VGroup(initial_brace, initial_labels)81        achilles_pos = 082        turtle_pos = 283 84        for i, step in enumerate(steps[1:], start=1):  # 从第二步开始85            # 移动阿基里斯86            achilles_pos = turtle_pos87            self.play(88                achilles.animate.move_to(number_line.number_to_point(achilles_pos) + UP * 0.5)89            )90            91            # 移动乌龟92            if i == 1:93                turtle_pos += 1  # 第二步乌龟移动1米94            elif i == 2:95                turtle_pos += 0.5  # 第三步乌龟移动0.5米96            elif i == 3:97                turtle_pos += 0.25  # 第四步乌龟移动0.25米98            99            self.play(100                turtle.animate.move_to(number_line.number_to_point(turtle_pos) + UP * 0.5)101            )102            103            # 修改标注部分104            new_brace = Brace(105                Line(106                    number_line.number_to_point(achilles_pos),107                    number_line.number_to_point(turtle_pos)108                ),109                UP,110                buff=0.1 * (i + 1)111            )112            113            # 根据步骤调整标注位置,显示距离和时间114            if i == len(steps) - 1:  # 最后一步115                new_labels = VGroup(116                    MathTex(f"s_{i+1} = {step['s']}").scale(0.4),117                    MathTex(f"t_{i+1} = {step['t']}").scale(0.4)118                ).arrange(DOWN, buff=0.1)119                new_labels.next_to(new_brace, UP, buff=0.1).shift(RIGHT * 0.5)120            else:121                new_labels = VGroup(122                    MathTex(f"s_{i+1} = {step['s']}").scale(0.4),123                    MathTex(f"t_{i+1} = {step['t']}").scale(0.4)124                ).arrange(DOWN, buff=0.1)125                new_labels.next_to(new_brace, UP, buff=0.1)126            127            braces_and_labels.add(new_brace, new_labels)128            129            self.play(130                Create(new_brace),131                Write(new_labels)132            )133            134            self.wait(1)135 136        self.wait(2)137 138        # 修改底部累加信息139        total_info = VGroup(140            # 路程累加141            MathTex(142                r"s_{\text{total}} = s_1 + s_2 + s_3 + s_4 + \cdots",143                r"= 2 + 1 + \frac{1}{2} + \frac{1}{4} + \cdots"144            ).scale(0.4),145            # 时间累加146            MathTex(147                r"t_{\text{total}} = t_1 + t_2 + t_3 + t_4 + \cdots",148                r"= 1 + \frac{1}{2} + \frac{1}{4} + \frac{1}{8} + \cdots"149            ).scale(0.4)150        ).arrange(DOWN, buff=0.3)151        152        # 将累加信息放在数轴下方153        total_info.next_to(number_line, DOWN, buff=1)154        155        # 修改古代表述部分156        ancient_text = VGroup(157            Text("古曰:", color=YELLOW).scale(0.5),158            Text("一尺之捶,日取其半,万世不竭", color=YELLOW).scale(0.5),159            VGroup(160                Text("即:", color=YELLOW).scale(0.4),161                MathTex(162                    r"1 + \frac{1}{2} + \frac{1}{4} + \frac{1}{8} + \cdots < 2"163                ).scale(0.4)164            ).arrange(RIGHT, buff=0.2)165        ).arrange(DOWN, buff=0.3)166        167        # 将古代表述放在数轴下方,在累加信息之后168        ancient_text.next_to(total_info, DOWN, buff=0.5)169        170        # 添加说明文字171        info_text = Text(172            "此过程将无限进行下去...", 173            color=YELLOW174        ).scale(0.4)175        info_text.next_to(ancient_text, DOWN, buff=0.3)176        177        self.play(Write(total_info))178        self.play(Write(ancient_text))179        self.play(Write(info_text))180        self.wait(2)181 182def main():183    scene = ZenoParadox()184    scene.render()185 186if __name__ == "__main__":187    main()

讲解

这个视频围绕「芝诺悖论」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。

画面中出现的文字「芝诺悖论:阿基里斯追乌龟」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。

核心公式可以写成:

vA=2v_A = 2

这类公式可以和画面中的符号一一对应。

观察路径

观察路径可以分三步:先锁定「芝诺悖论」中的核心对象,尤其留意芝诺悖论、无穷级数、数列收敛之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。

本页可以从芝诺悖论、无穷级数、数列收敛、极限过程这些概念进入,继续沿相邻问题观察同一类数学结构。