SymPy+Manim自动求解追及问题方程与动画联动实践
在制作物理追及问题的动画时,常需要根据题意手动列方程求相遇时间,再逐一计算每时刻坐标。参数(速度、初始距离、出发时间差)一旦改变,所有计算就得重来,过程繁琐且易错。本文基于 Python 的 SymPy 符号计算库,将列方程和求解自动化,并联动 Manim 动画引擎,实现任意参数下追及问题的自动求解与可视化。import sympy as sp
一、痛点场景
假设经典追及问题:甲从原点出发,速度 v1=2;乙从 x=10 处同向出发,速度 v2=5,问多久追上?若手工编写 Manim 动画,通常需要手动解方程:
5t = 10+2t → t=10/3
然后手动算出相遇位置,再硬编码轨迹函数。每次修改速度或初始距离,都需要重复上述过程,且容易在单位换算、正方向等细节上出错。
二、SymPy 自动求解
SymPy 可以将物理情景“翻译”成符号方程,自动求解。核心思路:定义时间符号 t,用符号表达式表示甲、乙的位置,令二者相等,调用 sp.solve() 直接得到相遇时间。
示例:同时出发,甲初始在乙前面 10 米,速度 v1=2,v2=5。
t = sp.symbols('t', positive=True)
v1, v2 = 2, 5
s0 = 10# 初始距离
pos1 = s0 + v1*t# 甲位置
pos2 = v2*t # 乙位置
eq = sp.Eq(pos1, pos2)
solution = sp.solve(eq, t)
print(solution)# 输出
若甲先出发 2 秒(即乙出发时甲已运动 2 秒),只需调整表达式:
t_delay = 2
pos1 = s0 + v1*(t + t_delay)
eq = sp.Eq(pos1, pos2)
solution = sp.solve(eq, t)
print(solution)# 输出
无论初始距离、速度差值还是出发延迟如何变化,只需修改符号表达式构建逻辑,求解交给 solve,相遇坐标代入即可获得精确值。
三、Manim 联动实战
将 SymPy 求解嵌入 Manim 动画场景,实现全自动追及动画。以下是一个完整示例,参数集中定义,动画完全自适应。
from manim import *
import sympy as sp
class CatchUpLab(Scene):
def construct(self):
# ====== 可修改参数 ======
v1 = 1.5 # 甲速度
v2 = 2.5 # 乙速度
init_gap = 8 # 初始距离(甲在乙前面)
delay = 1 # 甲早出发时间
# ====== SymPy 自动求解 ======
t = sp.symbols("t", positive=True)
pos1_expr = init_gap + v1 * (t + delay)
pos2_expr = v2 * t
eq = sp.Eq(pos1_expr, pos2_expr)
t_meet = sp.solve(eq, t)# 精确相遇时间
meet_x = float(pos2_expr.subs(t, t_meet))# 相遇位置
def pos1_func(time):
return init_gap + v1 * (time + delay)
def pos2_func(time):
return v2 * time
# ====== 场景搭建 ======
axes = NumberLine(
x_range=,
length=8,
include_numbers=True,
label_direction=DOWN,
)
self.play(Create(axes))
dot1 = Dot(color=RED, radius=0.2)
dot2 = Dot(color=BLUE, radius=0.2)
dot1.move_to(axes.number_to_point(pos1_func(0)))
dot2.move_to(axes.number_to_point(pos2_func(0)))
self.add(dot1, dot2)
label1 = Text("甲", color=RED).next_to(dot1, UP*2)
label2 = Text("乙", color=BLUE).next_to(dot2, UP*2)
self.add(label1, label2)
trace1 = TracedPath(dot1.get_center, stroke_color=RED, stroke_width=2)
trace2 = TracedPath(dot2.get_center, stroke_color=BLUE, stroke_width=2)
self.add(trace1, trace2)
meet_dot = Dot(point=axes.number_to_point(meet_x), color=YELLOW)
meet_label = Text(f"相遇点: {meet_x:.2f}", font_size=24, color=YELLOW)
meet_label.next_to(meet_dot, UP*1.5)
time_text = MathTex("t=0.0").shift(UL*2)
self.add(time_text)
total_time = float(t_meet) + 2
def update_dots(mob, alpha):
t_now = alpha * total_time
dot1.move_to(axes.number_to_point(pos1_func(t_now)))
dot2.move_to(axes.number_to_point(pos2_func(t_now)))
label1.next_to(dot1, UP*2)
label2.next_to(dot2, UP*2)
time_text.become(MathTex(f"t={t_now:.1f}").shift(UL*2))
if t_now >= float(t_meet):
self.add(meet_dot, meet_label)
self.play(
UpdateFromAlphaFunc(
VGroup(dot1, dot2, label1, label2, time_text),
update_dots,
run_time=total_time,
rate_func=linear,
)
)
self.wait(1)
关键设计:
- 所有参数集中在脚本开头,修改 v1、v2、init_gap、delay 即可改变题目,SymPy 自动重新求解相遇时间和位置,动画完全自适应。
- 使用 UpdateFromAlphaFunc 驱动动画,每帧根据当前时间计算两个点的坐标,坐标函数直接由 SymPy 表达式生成,精确无误差。
- 相遇点预先通过 sp.solve 得到精确值,当动画时间超过相遇时刻时,黄色标记出现,直观展示“乙追上甲”的瞬间。
- 未采用 always_redraw 而使用 UpdateFromAlphaFunc,更好地控制动画进度和时间显示,避免复杂依赖更新。
四、效果说明
运行上述场景,你将看到:一条水平数轴,红点(甲)在蓝点(乙)前方。动画开始后,两点同时向右移动,蓝点速度更快逐渐逼近红点。到达精确相遇时刻,黄色圆点出现在相遇位置并标注坐标,甲和乙重合。
若修改参数——例如甲速度从 1.5 改为 1.2,初始距离改为 12,甲提前出发 3 秒——只需修改脚本顶部几个数字,无需任何手动计算,动画仍准确呈现追及过程,并在正确位置标记相遇点。
注意:若参数设置导致无法追上(如乙速度小于甲),sp.solve 将返回空或负解,可在代码中增加判断逻辑,提示无法相遇,避免误标。
五、拓展思路
追及问题的自动化求解与动画联动,核心价值在于将“根据题意建立方程”和“求解”这两步程序化。对于其他行程问题(相遇、环形跑道、顺流逆流等),只要能将物理情景转化为代数方程,SymPy 就能自动解出关键节点,Manim 负责将节点转化为流畅的视觉呈现。两个工具分工明确,既精准又灵活。
(参考来源:脚本之家《Python使用SymPy自动求解追及问题的方程》)
Re: SymPy+Manim自动求解追及问题方程与动画联动实践
这个思路很实用!之前手动解方程确实容易在参数调整时反复改代码,SymPy 自动求解直接省掉了中间步骤,而且保持精确值,对非整数参数尤其友好。Manim 联动也做得干净,参数集中定义、函数自动生成,修改起来很舒服。 有一个小好奇:如果追及方向相反(比如相向而行),或者涉及加速度,这套框架能直接扩展吗?另外,遇到多解(比如超过一次相遇)时,`sp.solve` 会如何处理?Re: SymPy+Manim自动求解追及问题方程与动画联动实践
这个思路很实用!以前用 Manim 做追及动画确实经常手动解方程、硬编码轨迹,改参数就得从数学到代码全重来。SymPy 自动求解 + Manim 联动基本实现了一次封装、参数全动态。而且你贴的代码结构清晰,把参数定义、求解、动画分离,想改速度或延迟直接改变量就行,后续维护起来方便很多。 有个点想请教:如果遇到复杂情景(比如多段变速运动),SymPy 的 solve 处理分段函数或非线性方程表现如何?是否要考虑数值求解的回退方案?另外,动画里 `total_time` 直接取相遇时间 +2 秒,如果参数导致相遇时间很长(比如非常慢的追及),这个 +2 可能不够,是否会在 scene 里设置自动延长时间?Re: SymPy+Manim自动求解追及问题方程与动画联动实践
这个方法很实用,直接把符号求解和动画展示连起来,省去了每次手动列方程和调试轨迹的麻烦,对物理演示教学或者快速验证参量变化的影响都非常方便。代码结构也很清晰,把可变参数集中定义,后面自动解方程、生成轨迹,修改起来特别灵活。 想请教一下,如果是更复杂的情况,比如两物体运动方向相反、或者速度随时间变化(匀变速),这个框架能直接扩展吗?另外,SymPy 解出多个解(比如正解和负解)时,代码里是用 `` 取第一个,有没有考虑过根据场景自动筛选合理的解(比如时间非负且最小)?
页:
[1]