数学分析基础可视化

数列极限的epsilon-N语言

围绕数列极限的epsilon-N语言,观察epsilon-N 定义、数列极限、数列收敛之间的关系与推理路径。

打开原视频

epsilon_n_visualization.py
1from manim import *2import numpy as np3 4class EpsilonNVisualization(Scene):5    def construct(self):6        # Set default font7        Text.set_default(font="SimSun")8        9        # Title10        title = Text("极限的 ε-N 定义可视化", font="SimSun").scale(0.6)  # 缩小标题字体11        title.to_edge(UP, buff=0.3)12        self.play(Write(title))13        self.wait(1)14        15        # Fade out title16        self.play(FadeOut(title))17        18        # Problem statement with mathematical notation19        problem = MathTex(r"\lim_{n \to \infty} \frac{3n^2}{n^2 - 3} = 3").scale(1.0)  # 缩小题目字体20        problem.to_edge(UP, buff=0.3)21        22        self.play(Write(problem))23        self.wait(2)24        25        # Create axes for visualization26        axes = Axes(27            x_range=[0, 25, 5],28            y_range=[2, 4, 0.5],29            axis_config={"include_tip": True},30            x_length=8,  # 缩小图像宽度31            y_length=4   # 缩小图像高度32        )33        axes.next_to(problem, DOWN, buff=0.5)  # 下移一点点动画34        35        # Labels for axes36        x_label = MathTex("n").next_to(axes.x_axis, RIGHT, buff=0.3)37        y_label = MathTex("f(n)").next_to(axes.y_axis, UP, buff=0.3)38        39        self.play(Create(axes), Write(x_label), Write(y_label))40        self.wait(1)41        42        # Function to plot43        def func(x):44            return 3 * x**2 / (x**2 - 3)45        46        # 先显示数列散点图,按照n为正整数取值绘制点47        points = VGroup()48        x_values = range(2, 26)  # 正整数n从2到2549        for x in x_values:50            y = func(x)51            point = Dot(axes.c2p(x, y), color=BLUE, radius=0.05)52            points.add(point)53        54        graph_label = MathTex(r"f(n) = \frac{3n^2}{n^2 - 3}").next_to(axes.c2p(20, func(20)), UP, buff=0.2).scale(0.7)55        graph_label.set_color(BLUE)56        57        # Plot the limit line y = 358        limit_line = axes.plot(lambda x: 3, x_range=[0, 25], color=GREEN)59        limit_label = MathTex("y = 3").next_to(limit_line.get_end(), DOWN, buff=0.2).scale(0.7)60        limit_label.set_color(GREEN)61        62        self.play(Create(points), Write(graph_label))63        self.play(Create(limit_line), Write(limit_label))64        self.wait(2)65        66        # 然后显示N的推导过程67        # 添加一般形式的推导过程68        derivation_title = Text("N 的一般形式推导过程:", font="SimSun").scale(0.4)  # 缩小字体69        derivation_title.to_corner(UL, buff=0.3)  # 调整位置70        derivation_title.shift(DOWN * 1.2)  # 下移一点点71        72        derivation_step1 = MathTex(r"|f(n) - 3| = \left|\frac{9}{n^2 - 3}\right|").scale(0.4)  # 缩小字体73        derivation_step2_part1 = Text("当", font="SimSun").scale(0.4)74        derivation_step2_part2 = MathTex(r"n > \sqrt{3}").scale(0.4)75        derivation_step2_part3 = Text("时", font="SimSun").scale(0.4)76        derivation_step2_part4 = MathTex(r"\frac{9}{n^2 - 3} < \varepsilon").scale(0.4)77        78        # 组合 derivation_step279        derivation_step2 = VGroup(derivation_step2_part1, derivation_step2_part2, derivation_step2_part3, derivation_step2_part4)80        derivation_step2.arrange(RIGHT, buff=0.1)81        82        derivation_step3 = MathTex(r"n^2 - 3 > \frac{9}{\varepsilon}").scale(0.4)  # 缩小字体83        derivation_step4 = MathTex(r"n^2 > \frac{9}{\varepsilon} + 3").scale(0.4)  # 缩小字体84        derivation_step5 = MathTex(r"n > \sqrt{\frac{9}{\varepsilon} + 3}").scale(0.4)  # 缩小字体85        86        derivation_step6_part1 = Text("因此", font="SimSun").scale(0.4)87        derivation_step6_part2 = MathTex(r"N = \left\lceil \sqrt{\frac{9}{\varepsilon} + 3} \right\rceil").scale(0.4)88        89        # 组合 derivation_step690        derivation_step6 = VGroup(derivation_step6_part1, derivation_step6_part2)91        derivation_step6.arrange(RIGHT, buff=0.1)92        93        derivation_group = VGroup(derivation_title, derivation_step1, derivation_step2, derivation_step3, derivation_step4, derivation_step5, derivation_step6)94        derivation_group.arrange(DOWN, aligned_edge=LEFT, buff=0.1)  # 减小行间距95        derivation_group.to_corner(UL, buff=0.3)  # 调整位置96        derivation_group.shift(DOWN * 1.2)  # 下移一点点97        98        self.play(Write(derivation_title))99        self.wait(1)100        self.play(Write(derivation_step1))101        self.wait(1)102        self.play(Write(derivation_step2_part1), Write(derivation_step2_part2), Write(derivation_step2_part3), Write(derivation_step2_part4))103        self.wait(1)104        self.play(Write(derivation_step3))105        self.wait(1)106        self.play(Write(derivation_step4))107        self.wait(1)108        self.play(Write(derivation_step5))109        self.wait(1)110        self.play(Write(derivation_step6_part1), Write(derivation_step6_part2))111        self.wait(2)112        113        # Show different epsilon values and corresponding N calculations114        epsilons = [0.5, 0.15]115        colors = [RED, ORANGE]116        highlight_colors = [YELLOW, PURPLE]117        118        for i, (epsilon, color, highlight_color) in enumerate(zip(epsilons, colors, highlight_colors)):119            # Calculate N for this epsilon120            N_float = np.sqrt(9/epsilon + 3)121            N = int(np.ceil(N_float))  # Take the ceiling of N122            123            # 将N具体数值的计算移到右上角124            if i == 0:125                # For first epsilon, show full calculation126                n_value_title = Text(f"当ε = {epsilon}时:", font="SimSun").scale(0.4)  # 缩小字体127                n_value_title.to_corner(UR, buff=0.3)  # 调整位置到右上角128                n_value_title.shift(DOWN * 0.5)  # 下移一点点129                130                n_value_step1 = MathTex(f"N = \\left\\lceil \\sqrt{{\\frac{{9}}{{{epsilon}}} + 3}} \\right\\rceil").scale(0.5)  # 缩小字体131                n_value_step2 = MathTex(f"N = \\left\\lceil {N_float:.2f} \\right\\rceil = {N}").scale(0.5)  # 缩小字体132                133                n_value_group = VGroup(n_value_title, n_value_step1, n_value_step2)134                n_value_group.arrange(DOWN, aligned_edge=LEFT, buff=0.1)  # 减小行间距135                n_value_group.to_corner(UR, buff=0.3)  # 调整位置到右上角136                n_value_group.shift(DOWN * 0.5)  # 下移一点点137                138                self.play(Write(n_value_title))139                self.play(Write(n_value_step1))140                self.wait(0.5)141                self.play(Write(n_value_step2))142                self.wait(1)143                144                n_value_group_prev = n_value_group145            else:146                # For second epsilon, just show the result147                n_result_part1 = Text("当", font="SimSun").scale(0.4)148                n_result_part2 = MathTex(r"\varepsilon").scale(0.4)149                n_result_part3 = Text(f"= {epsilon}时,N = {N}", font="SimSun").scale(0.4)150                151                n_result = VGroup(n_result_part1, n_result_part2, n_result_part3)152                n_result.arrange(RIGHT, buff=0.1)153                n_result.to_corner(UR, buff=0.3)  # 调整位置到右上角154                n_result.shift(DOWN * 0.5)  # 下移一点点155                156                self.play(Transform(n_value_group_prev, n_result))157                self.wait(2)158            159            # 最后显示y=3+epsilon和y=3-epsilon的直线160            upper_epsilon_line = axes.plot(lambda x: 3 + epsilon, x_range=[0, 25], color=color)161            lower_epsilon_line = axes.plot(lambda x: 3 - epsilon, x_range=[0, 25], color=color)162            163            upper_epsilon_label = MathTex(f"y = 3 + \\varepsilon = {3 + epsilon}").next_to(upper_epsilon_line.get_end(), UP, buff=0.1).scale(0.6)164            upper_epsilon_label.set_color(color)165            lower_epsilon_label = MathTex(f"y = 3 - \\varepsilon = {3 - epsilon}").next_to(lower_epsilon_line.get_end(), DOWN, buff=0.1).scale(0.6)166            lower_epsilon_label.set_color(color)167            168            if i == 0:169                # Show epsilon lines and labels170                self.play(Create(upper_epsilon_line), Create(lower_epsilon_line))171                self.play(Write(upper_epsilon_label), Write(lower_epsilon_label))172                self.wait(2)173            else:174                # Transform to new epsilon lines175                self.play(176                    Transform(upper_epsilon_line_prev, upper_epsilon_line),177                    Transform(lower_epsilon_line_prev, lower_epsilon_line),178                    Transform(upper_epsilon_label_prev, upper_epsilon_label),179                    Transform(lower_epsilon_label_prev, lower_epsilon_label)180                )181                self.wait(2)182            183            # Store references for next iteration184            upper_epsilon_line_prev = upper_epsilon_line185            lower_epsilon_line_prev = lower_epsilon_line186            upper_epsilon_label_prev = upper_epsilon_label187            lower_epsilon_label_prev = lower_epsilon_label188            189            # 2. Then show the absolute value |f(n) - 3|190            if i == 0:191                # Create a vertical brace between the epsilon lines in the middle of the graph, on the left side192                epsilon_brace = BraceBetweenPoints(193                    axes.c2p(10, 3 + epsilon),194                    axes.c2p(10, 3 - epsilon),195                    color=color,196                    direction=LEFT  # Point brace to the left197                )198                epsilon_condition = MathTex(f"|f(n) - 3| < \\varepsilon = {epsilon}").scale(0.7)199                epsilon_condition.next_to(epsilon_brace, LEFT, buff=0.2)200                epsilon_condition.set_color(color)201                202                self.play(Create(epsilon_brace), Write(epsilon_condition))203                epsilon_brace_prev = epsilon_brace204                epsilon_condition_prev = epsilon_condition205                self.wait(2)206            else:207                # Update epsilon condition208                new_epsilon_brace = BraceBetweenPoints(209                    axes.c2p(10, 3 + epsilon),210                    axes.c2p(10, 3 - epsilon),211                    color=color,212                    direction=LEFT  # Point brace to the left213                )214                new_epsilon_condition = MathTex(f"|f(n) - 3| < \\varepsilon = {epsilon}").scale(0.7)215                new_epsilon_condition.next_to(new_epsilon_brace, LEFT, buff=0.2)216                new_epsilon_condition.set_color(color)217                218                self.play(219                    Transform(epsilon_brace_prev, new_epsilon_brace),220                    Transform(epsilon_condition_prev, new_epsilon_condition)221                )222                self.wait(2)223            224            # Draw vertical line at N225            N_line = axes.get_vertical_line(226                axes.c2p(N, 0),227                line_config={"color": highlight_color, "stroke_width": 4}228            )229            N_label = MathTex(f"N = {N}").next_to(N_line, UP, buff=0.1).scale(0.7)230            N_label.set_color(highlight_color)231            232            # Create a dotted vertical line spanning the entire y-range for better visibility233            N_dotted_line = DashedLine(234                start=axes.c2p(N, axes.get_y_range()[0]),235                end=axes.c2p(N, axes.get_y_range()[1]),236                color=highlight_color,237                stroke_width=2,238                dash_length=0.1239            )240            241            if i == 0:242                # Show N line243                self.play(Create(N_dotted_line))244                self.play(Create(N_line), Write(N_label))245                self.wait(1)246                247                # Store references248                N_line_prev = N_line249                N_label_prev = N_label250                N_dotted_line_prev = N_dotted_line251            else:252                # Move N line to new position253                self.play(254                    Transform(N_dotted_line_prev, N_dotted_line),255                    Transform(N_line_prev, N_line),256                    Transform(N_label_prev, N_label)257                )258                self.wait(1)259            260            # 高亮满足条件的点261            highlight_points = VGroup()262            for x in x_values:263                if x > N:264                    y = func(x)265                    point = Dot(axes.c2p(x, y), color=highlight_color, radius=0.07)266                    highlight_points.add(point)267            268            if i == 0:269                # Show highlight270                self.play(Create(highlight_points))271                highlight_points_prev = highlight_points272                self.wait(2)273            else:274                # Update highlight275                self.play(Transform(highlight_points_prev, highlight_points))276                self.wait(2)277        278        # Show the relationship between epsilon and N279        relationship = MathTex(280            "\\varepsilon \\downarrow \\quad \\Rightarrow \\quad N \\uparrow",281            color=YELLOW282        ).scale(1.0)  # 缩小字体283        relationship.to_edge(DOWN, buff=0.7)  # 下移一点点284        285        self.play(Write(relationship))286        self.wait(2)287        288        # Final conclusion289        conclusion = Text(290            "当ε减小时,满足条件的N必须增大,这体现了极限的ε-N定义本质",291            font="SimSun"292        ).scale(0.5)  # 缩小字体293        conclusion.next_to(relationship, DOWN, buff=0.3)  # 调整位置和间距294        295        self.play(Write(conclusion))296        self.wait(3)297 298def main():299    scene = EpsilonNVisualization()300    scene.render()301 302if __name__ == "__main__":303    main()

讲解

这个视频围绕「数列极限的epsilon-N语言」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

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

画面中出现的文字「极限的 ε-N 定义可视化」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

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

核心公式可以写成:

limn3n2n23=3\lim_{n \to \infty} \frac{3n^2}{n^2 - 3} = 3

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

观察路径

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

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