数学分析基础可视化

数列的收敛性演示

围绕数列的收敛性演示,观察数列收敛、epsilon-N 定义、函数图像之间的关系与推理路径。

打开原视频

sequence_convergence.py
1from manim import *2import numpy as np3 4class SequenceConvergence(Scene):5    def construct(self):6        # 创建标题7        title = Text("数列的收敛性演示", font="SimSun", font_size=36)8        title.to_edge(UP)9        self.play(Write(title))10        self.wait(1)11 12        # 创建坐标系13        axes = Axes(14            x_range=[0, 20, 5],15            y_range=[-0.5, 2, 0.5],16            axis_config={"color": GREY},17            x_length=10,18            y_length=619        ).shift(DOWN * 0.2)20        21        axes_labels = axes.get_axis_labels(22            x_label="n",23            y_label="a_n"24        )25 26        self.play(Create(axes), Write(axes_labels))27        self.wait(1)28 29        # 创建收敛数列 an = 1 + 1/n30        def converge_seq(n):31            return 1 + 1/n if n > 0 else 232 33        converge_points = [axes.c2p(n, converge_seq(n)) for n in range(1, 21)]34        converge_dots = VGroup(*[Dot(point, color=BLUE) for point in converge_points])35        36        # 创建连线37        converge_lines = VMobject(color=BLUE_A, stroke_width=2)38        converge_lines.set_points_smoothly(converge_points)39 40        converge_label = MathTex(41            r"a_n",42            color=BLUE43        ).scale(0.8).to_edge(UP, buff=1.5).to_edge(RIGHT, buff=1.0)44 45        # 创建振荡数列 bn = (-1)^n/n + 146        def oscillate_seq(n):47            return (-1)**n/n + 1 if n > 0 else 1.548 49        oscillate_points = [axes.c2p(n, oscillate_seq(n)) for n in range(1, 21)]50        oscillate_dots = VGroup(*[Dot(point, color=RED) for point in oscillate_points])51        52        oscillate_lines = VMobject(color=RED_A, stroke_width=2)53        oscillate_lines.set_points_as_corners(oscillate_points)54 55        oscillate_label = MathTex(56            r"b_n",57            color=RED58        ).scale(0.8).next_to(converge_label, DOWN, buff=0.3)59 60        # 显示收敛数列61        self.play(Write(converge_label))62        for i in range(len(converge_dots)):63            self.play(64                Create(converge_dots[i]),65                Create(converge_lines) if i == len(converge_dots)-1 else Wait(),66                run_time=0.267            )68        self.wait(1)69 70        # 显示振荡数列71        self.play(Write(oscillate_label))72        for i in range(len(oscillate_dots)):73            self.play(74                Create(oscillate_dots[i]),75                Create(oscillate_lines) if i == len(oscillate_dots)-1 else Wait(),76                run_time=0.277            )78        self.wait(1)79 80        # 添加极限线81        limit_line = DashedLine(82            axes.c2p(0, 1),83            axes.c2p(20, 1),84            color=YELLOW85        )86        limit_label = MathTex(87            r"\lim_{n \to \infty} a_n = \lim_{n \to \infty} b_n = a", 88            color=YELLOW89        ).next_to(limit_line, RIGHT, buff=0.2).shift(DOWN * 1 + LEFT * 5)90 91        self.play(92            Create(limit_line),93            Write(limit_label)94        )95        self.wait(1)96 97        # 创建动态ε带和N标注的更新函数98        def update_epsilon_band(epsilon_val):99            # 更新ε带100            upper_line = DashedLine(101                axes.c2p(0, 1 + epsilon_val),102                axes.c2p(20, 1 + epsilon_val),103                color=GREEN_A104            )105            middle_line = DashedLine(  # 添加中间线106                axes.c2p(0, 1),107                axes.c2p(20, 1),108                color=YELLOW,109                dash_length=0.1110            )111            lower_line = DashedLine(112                axes.c2p(0, 1 - epsilon_val),113                axes.c2p(20, 1 - epsilon_val),114                color=GREEN_A115            )116            117            # 添加标注118            upper_label = MathTex(r"a+\varepsilon", color=GREEN_A).next_to(119                axes.c2p(0, 1 + epsilon_val), LEFT120            )121            middle_label = MathTex(r"a", color=YELLOW).next_to(122                axes.c2p(0, 1), LEFT123            )124            lower_label = MathTex(r"a-\varepsilon", color=GREEN_A).next_to(125                axes.c2p(0, 1 - epsilon_val), LEFT126            )127            128            epsilon_brace = BraceBetweenPoints(129                axes.c2p(19, 1 + epsilon_val),130                axes.c2p(19, 1 - epsilon_val),131                color=GREEN_A,132                direction=RIGHT133            )134            epsilon_text = MathTex(r"2\varepsilon", color=GREEN_A).next_to(epsilon_brace, RIGHT)135 136            # 计算对应的N值137            # 对于an = 1 + 1/n,要使|an - 1| < ε,需要n > 1/ε138            N_value = max(5, int(1/epsilon_val))139 140            # 添加N处的垂直虚线141            N_line = DashedLine(142                axes.c2p(N_value, 0),143                axes.c2p(N_value, 2),  # 延伸到足够高144                color=GREEN,145                dash_length=0.1146            )147 148            # 简化N标签149            N_arrow = Arrow(150                axes.c2p(N_value, -0.3),151                axes.c2p(N_value, 0),152                color=GREEN,153                buff=0154            )155            N_label = MathTex(r"N", color=GREEN).next_to(N_arrow, DOWN)156 157            return VGroup(158                upper_line, middle_line, lower_line,159                upper_label, middle_label, lower_label,160                epsilon_brace, epsilon_text,161                N_line, N_arrow, N_label162            )163 164        # 创建动画序列165        epsilon_values = [0.5, 0.3, 0.2, 0.1]166        epsilon_bands = []167        168        # 显示初始ε带169        current_band = update_epsilon_band(epsilon_values[0])170        self.play(Create(current_band))171        self.wait(1)172 173        # 动态更新ε带和N174        for i in range(1, len(epsilon_values)):175            new_band = update_epsilon_band(epsilon_values[i])176            self.play(177                ReplacementTransform(current_band, new_band),178                run_time=2179            )180            current_band = new_band181            self.wait(1)182 183        # 修改解释文本的位置和大小184        explanation = Text(185            "数列收敛的定义:\n" + 186            "∀ε>0, ∃N>0, 当n>N时," +187            "|an-a| < ε" +188            "其中a是数列的极限。" +189            "注意:ε越小,N越大",190            font="SimSun",191            font_size=22,  # 稍微减小字体192            line_spacing=1.1  # 稍微减小行距193        ).next_to(194            axes,  # 只相对于坐标系定位,不包括current_band195            DOWN,196            buff=0.3  # 减小间距197        ).align_to(axes, LEFT).shift(UP * 0.5)  # 整体上移一点198 199        # 创建背景矩形,确保文字清晰可见200        explanation_bg = BackgroundRectangle(201            explanation,202            color=BLACK,203            fill_opacity=0.8,204            buff=0.2205        )206 207        # 先显示背景,再显示文字208        self.play(209            FadeIn(explanation_bg),210            Write(explanation)211        )212        self.wait(2)213def main():214    import os215    os.system("manim -pqh sequence_convergence.py SequenceConvergence")216 217if __name__ == "__main__":218    main()

讲解

这个视频围绕「数列的收敛性演示」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

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

画面中出现的文字「数列的收敛性演示」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

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

核心公式可以写成:

a+εa+\varepsilon

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

观察路径

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

本页可以从数列收敛、epsilon-N 定义、函数图像这些概念进入,继续沿相邻问题观察同一类数学结构。