向量分析可视化

向量场通量的计算

围绕向量场通量的计算,观察通量、曲面积分、向量场之间的关系与推理路径。

打开原视频

surface_flux.py
1from manim import *2import numpy as np3 4config.tex_template = TexTemplateLibrary.ctex5config.tex_template.add_to_preamble(r"\setCJKmainfont{STSong}")6 7class SurfaceFlux(ThreeDScene):8    def construct(self):9        # 创建标题10        title = Text("向量场通量的计算", font="STSong", font_size=48)11        self.add_fixed_in_frame_mobjects(title)12        self.play(Write(title))13        self.wait(1)14        self.play(FadeOut(title))15 16        # 创建3D坐标系17        left_axes = ThreeDAxes(18            x_range=[-2, 2, 1],19            y_range=[-2, 2, 1],20            z_range=[0, 2, 1],21            x_length=4,  # 缩小左侧坐标系22            y_length=4,23            z_length=424        ).shift(LEFT * 3)  # 向左移动25 26        right_axes = ThreeDAxes(27            x_range=[-2, 2, 1],28            y_range=[-2, 2, 1],29            z_range=[0, 2, 1],30            x_length=4,  # 右侧坐标系大小相同31            y_length=4,32            z_length=433        ).shift(RIGHT * 3)  # 向右移动34 35        # 设置一个稍微倾斜的固定视角,便于同时观察平面和曲面36        self.set_camera_orientation(37            phi=75*DEGREES,  # 稍微抬高视角38            theta=270*DEGREES  # 旋转270度(相当于-90度),从另一侧观察39        )40 41        # 显示坐标系42        self.play(Create(left_axes), Create(right_axes))43        self.wait(2)44 45        # 第一部分:平面通量演示46        # 创建平面 z = 147        plane = Surface(48            lambda u, v: left_axes.c2p(u, v, 0),  # 改为z=0平面49            u_range=[-2, 2],50            v_range=[-2, 2],51            resolution=(10, 10),52            fill_opacity=0.5,53            color=BLUE54        )55        56        self.play(Create(plane))57        self.wait(1)58 59        # 创建平面上的法向量场(只显示几个代表性向量)60        normal_vectors = VGroup()61        for u, v in [(-0.8, -0.8), (-0.8, 0.8), (0.8, -0.8), (0.8, 0.8), (0, 0)]:62            point = left_axes.c2p(u, v, 0)  # 改为z=0平面上的点63            normal = np.array([0, 0, 1])64            vector = Arrow3D(65                start=point,66                end=point + normal * 0.5,67                color=YELLOW,68                thickness=0.0269            )70            normal_vectors.add(vector)71 72        # 显示法向量场73        self.play(74            Create(normal_vectors),75            run_time=176        )77        self.wait(2)78 79        # 显示法向量标注80        normal_text = MathTex(81            "\\text{法向量}\\,\\vec{n}",82            color=YELLOW83        ).scale(0.6).to_corner(UL)84        self.add_fixed_in_frame_mobjects(normal_text)85        self.play(Write(normal_text))86        self.wait(1)87 88        # 创建向量场 F = (0, 0, z)89        def get_vector_field(u, v, z):90            return np.array([1, 1, 1])  # 统一方向的向量场,指向(1,1,1)91 92        field_vectors = VGroup()93        for u, v in [(-0.8, -0.8), (-0.8, 0.8), (0.8, -0.8), (0.8, 0.8), (0, 0)]:94            point = left_axes.c2p(u, v, 0)95            field = get_vector_field(u, v, 0)96            # 归一化向量场97            norm = np.linalg.norm(field)98            if norm > 0:99                field = field / norm * 0.5100            vector = Arrow3D(101                start=point,102                end=point + field,103                color=RED,104                thickness=0.03105            )106            vector.set_fill(RED, opacity=0.8)107            field_vectors.add(vector)108 109        # 显示向量场110        self.play(111            *[Create(vec) for vec in field_vectors],112            run_time=1113        )114        self.wait(2)115 116        # 显示向量场标注117        field_desc = MathTex(118            "\\text{向量场}\\,\\vec{F}",119            color=RED120        ).scale(0.6).next_to(normal_text, DOWN, buff=0.3)121        self.add_fixed_in_frame_mobjects(field_desc)122        self.play(Write(field_desc))123        self.wait(1)124 125        # 显示平面通量计算公式126        flux_formula = MathTex(127            "\\text{通量}\\Phi = \\vec{F} \\cdot \\vec{n} \\, S"128        ).scale(0.6).next_to(field_desc, DOWN, buff=0.3)129        self.add_fixed_in_frame_mobjects(flux_formula)130        self.play(Write(flux_formula))131        self.wait(1)132 133        # 第二部分:曲面通量演示134        # 创建抛物面 z = 0.1(x² + y²)135        surface = Surface(136            lambda u, v: right_axes.c2p(u, v, 0.1*(u**2 + v**2)),137            u_range=[-2, 2],138            v_range=[-2, 2],139            resolution=(10, 10),140            checkerboard_colors=[BLUE_D, BLUE_E],141            fill_opacity=0.7142        )143        self.play(Create(surface))144        self.wait(1)145 146        # 定义法向量计算函数147        def get_normal_vector(u, v):148            # 计算曲面在点(u,v)处的法向量149            tangent_u = np.array([1, 0, 0.2*u])  # 修改系数150            tangent_v = np.array([0, 1, 0.2*v])151            normal = np.cross(tangent_u, tangent_v)152            normal = normal / np.linalg.norm(normal)153            return normal154 155        # 定义向量场函数156        def get_vector_field(u, v):157            point = np.array([u, v, 0.1*(u**2 + v**2)])  # 修改系数158            return point159 160        # 创建法向量场161        normal_vectors = VGroup()162        for u, v in [(-0.8, -0.8), (-0.8, 0.8), (0.8, -0.8), (0.8, 0.8), (0, 0)]:163            point = right_axes.c2p(u, v, 0.1*(u**2 + v**2))164            normal = get_normal_vector(u, v)165            vector = Arrow3D(166                start=point,167                end=point + normal * 0.5,168                color=YELLOW,169                thickness=0.03170            )171            vector.set_fill(YELLOW, opacity=0.8)172            normal_vectors.add(vector)173 174        # 修改显示法向量场的方式175        self.play(176            *[Create(vec) for vec in normal_vectors],177            run_time=1178        )179        self.wait(0.3)180 181        # 创建向量场(同样减少向量数量)182        field_vectors = VGroup()183        for u, v in [(-0.8, -0.8), (-0.8, 0.8), (0.8, -0.8), (0.8, 0.8), (0, 0)]:184            point = right_axes.c2p(u, v, 0.1*(u**2 + v**2))185            field = get_vector_field(u, v)186            # 归一化向量场,避免太长187            norm = np.linalg.norm(field)188            if norm > 0:189                field = field / norm * 0.5190            vector = Arrow3D(191                start=point,192                end=point + field,193                color=RED,194                thickness=0.03195            )196            # 设置向量的填充不透明度197            vector.set_fill(RED, opacity=0.8)198            field_vectors.add(vector)199 200        # 修改显示向量场的方式201        self.play(202            *[Create(vec) for vec in field_vectors],203            run_time=1204        )205        self.wait(2)206 207        # 添加向量场说明208        field_desc = MathTex(209            "\\text{法向量}\\,\\vec{n}",210            color=YELLOW211        ).scale(0.7).to_corner(UR)212        self.add_fixed_in_frame_mobjects(field_desc)213        214        field_desc2 = MathTex(215            "\\text{向量场}\\,\\vec{F}",216            color=RED217        ).scale(0.7).next_to(field_desc, DOWN, buff=0.3)218        self.add_fixed_in_frame_mobjects(field_desc2)219        220        self.play(221            Write(field_desc),222            Write(field_desc2)223        )224        self.wait(1)225 226        # 添加微元演示227        micro_u, micro_v = 1.0, 1.0  # 选择曲面上更倾斜的位置228        du, dv = 0.2, 0.2  # 微元大小229 230        # 创建放大的微元框架231        micro_frame = ThreeDAxes(232            x_range=[-0.5, 0.5, 0.2],233            y_range=[-0.5, 0.5, 0.2],234            z_range=[0, 0.5, 0.1],235            x_length=2,236            y_length=2,237            z_length=1238        ).shift(DOWN * 6).set_opacity(0)239        240        # 获取原曲面上微元中心点的坐标241        original_point = right_axes.c2p(micro_u, micro_v, 0.1*(micro_u**2 + micro_v**2))242        243        # 创建并显示放大框和连接线244        zoom_box = Rectangle(245            height=1,246            width=1,247            color=YELLOW248        ).set_fill(BLACK, opacity=0.1)249        zoom_box.move_to(original_point)250        251        zoom_lines = VGroup(252            Line(253                original_point,254                micro_frame.get_origin(),255                color=YELLOW,256                stroke_width=0.5257            )258        )259 260        # 计算微元处的法向量,用于确定微元的倾斜角度261        normal = get_normal_vector(micro_u, micro_v)262        # 计算微元平面的旋转矩阵263        z_axis = np.array([0, 0, 1])264        rotation_axis = np.cross(z_axis, normal)265        rotation_angle = np.arccos(np.dot(z_axis, normal))266        267        # 旋转微元框架268        if np.linalg.norm(rotation_axis) > 1e-6:  # 避免零向量269            rotation_axis = rotation_axis / np.linalg.norm(rotation_axis)270            micro_frame.rotate(angle=rotation_angle, axis=rotation_axis)271 272        # 在原曲面上标记微元区域273        highlight_box = Surface(274            lambda u, v: right_axes.c2p(275                micro_u + u*du, micro_v + v*du, 276                0.1*((micro_u + u*du)**2 + (micro_v + v*du)**2)277            ),278            u_range=[-0.5, 0.5],279            v_range=[-0.5, 0.5],280            resolution=(2, 2),281            fill_opacity=0.3,282            color=YELLOW283        )284 285        self.play(286            Create(zoom_box),287            Create(zoom_lines),288            Create(highlight_box)289        )290        self.wait(1)291 292        # 创建微元区域(保持与原曲面相同的倾斜角度)293        micro_surface = Surface(294            lambda u, v: micro_frame.c2p(295                u, v, 296                0  # 在旋转后的坐标系中,微元近似为平面297            ),298            u_range=[-0.5, 0.5],299            v_range=[-0.5, 0.5],300            resolution=(2, 2),301            fill_opacity=0.8,302            color=YELLOW_A303        )304 305        self.play(306            Create(micro_surface)307        )308        self.wait(1)309 310        # 在微元上显示向量场和法向量311        center_point = micro_frame.c2p(0, 0, 0)312        micro_normal = Arrow3D(313            start=center_point,314            end=center_point + normal * 1,315            color=YELLOW,316            thickness=0.03317        )318 319        field = get_vector_field(micro_u, micro_v)320        field = field / np.linalg.norm(field) * 1321        micro_field = Arrow3D(322            start=center_point,323            end=center_point + field,324            color=RED,325            thickness=0.03326        )327 328        self.play(329            Create(micro_normal),330            Create(micro_field)331        )332        self.wait(2)333 334        # 添加说明文字335        micro_text = Text(336            "曲面微元可近似为平面",337            font="STSong",338            font_size=24339        ).shift(DOWN * 2.5+RIGHT*3.5)340        self.add_fixed_in_frame_mobjects(micro_text)341 342        # 显示平面近似343        self.play(344            Write(micro_text),345            run_time=1346        )347        self.wait(2)348 349        # 显示微元通量计算公式和最后的结论(在同一行)350        micro_flux_formula = MathTex(351            "d\\Phi = \\vec{F} \\cdot \\vec{n} \\, dS"352        ).scale(0.6).shift(DOWN * 3.5).shift(LEFT * 2)  # 放在左侧353        self.add_fixed_in_frame_mobjects(micro_flux_formula)354        self.play(Write(micro_flux_formula))355        self.wait(2)356 357        358 359        # 最后的结论360        conclusion = MathTex(361            "\\text{通量} = \\iint_S \\vec{F} \\cdot \\vec{n} \\, dS"362        ).scale(0.6).shift(DOWN * 3.5).shift(RIGHT * 2)  # 放在右侧363        self.add_fixed_in_frame_mobjects(conclusion)364        self.play(Write(conclusion))365        self.wait(3)366 367        # 最后多等待一会,让观众有时间观察368        self.wait(1)369 370def main():371    import os372    os.system("manim -pqh surface_flux.py SurfaceFlux")373 374if __name__ == "__main__":375    main()

讲解

这个视频围绕「向量场通量的计算」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

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

画面中出现的文字「向量场通量的计算」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

观察路径

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

本页可以从通量、曲面积分、向量场、法向量、微元法这些概念进入,继续沿相邻问题观察同一类数学结构。