最近在做Fourier Transform的内容,记录一下今天下午的成果。
本文代码全部自行编写,需要math and music项目完整工程可以在gayhub上获取。(现在还没弄完,就先不发了。)
概要
第一部分:
图像代码部分原理很直接,即极坐标参数方程的转化。
第二部分:
关于图像质点中心的问题,数学上需要使用复数与微积分的知识求出。
3b1b的原代码也是将质点的x-coordinate of center of mass图像直接用公式绘制。
但是本文使用的是暴力的方法,直接用Mobject的get_center通过帧updater描点的方法绘制离散的点集。如果需要,可以拟合为曲线。
原视频:https://www.youtube.com/watch?v=spUNpyF58BY&t=188s
bilibili:
https://www.bilibili.com/video/BV1pW411J7s8?share_source=copy_web
数学公式在geogebra中构建如下:
即将cos(mx)+1
转化为参数方程[(1+cos(mt))·cos(nt),(1+cos(mt))·sin(nt)]
manim代码:
创建的Mobject有:axes
axes_label
polarPlane
D_delta
D_rou
D_move
以及三个图像:axes_graph
polar_graph
para_graph
然后使用add_update()添加DecimalNumber作为变化数值到动画更新函数即可。
第一部分代码:
class FourierTrans_First(Scene): def construct(self): axes = Axes( x_range=[-0, 2*PI, PI/4], y_range=[-0.1, 2.5, 1], x_length=14, y_length=2 ).to_edge(UP) axes_label = axes.get_axis_labels('Time','Intensity') polarPlane = PolarPlane( radius_max=2.0, azimuth_units="TAU radians", size=4, azimuth_label_font_size=24, radius_config={"font_size": 24}, ).add_coordinates().to_edge(DOWN+LEFT) #显示坐标与坐标标签 self.add(axes,axes_label,polarPlane) #一些全局参数-修改这三个参数就好 delta = 0#偏移量 rou = 20#theta的系数 move = 10#极坐标变换的变化程度系数 dn_kwargs = {'num_decimal_places':3,} D_delta = DecimalNumber(delta,**dn_kwargs) D_rou = DecimalNumber(rou,**dn_kwargs) D_move = DecimalNumber(move,**dn_kwargs).shift(DOWN) #解析式-公式修改这里就好 r = lambda t: np.sin(D_rou.get_value()*t)+1 par = lambda t: np.array([ (r(t))*np.cos(D_move.get_value()*t), (r(t))*np.sin(D_move.get_value()*t), 0]) #更新函数 def Func_axes(): return axes.plot(r,color=PINK) def Func_polar(): return polarPlane.plot_polar_graph(r, [0, 2 * PI], color=ORANGE) def Func_para(): para = ParametricFunction( par, t_range = np.array([0, 3.14*2]), fill_opacity=0)\ .set_color(color=[RED,YELLOW,BLUE,RED])\ .shift(DOWN*2+RIGHT*2) self.add(Dot(para.get_center())) return para axes_graph = Func_axes() polar_graph = Func_polar() para_graph = Func_para() axes_graph.add_updater(lambda mob: mob.become(Func_axes())) polar_graph.add_updater(lambda mob: mob.become(Func_polar())) para_graph.add_updater(lambda mob:mob.become(Func_para())) self.add(D_rou,D_move) self.play(Write(axes_graph),Write(polar_graph),Write(para_graph)) #self.play(ChangeDecimalToValue(D_rou,20),run_time=5,rate_func=linear) self.play(ChangeDecimalToValue(D_move,20),run_time=5,rate_func=linear) self.wait(1)
第二部分(含一)代码:
from manim import * class FourierTrans_First(Scene): def construct(self): #########全局参数-修改这5个参数就好######### delta = 0#偏移量 rou = 0#theta的系数 move = 1#极坐标变换的变化程度系数 target = 1#追踪质心y坐标 track_end = 18#扭扭的结尾 ############################################ dn_kwargs = {'num_decimal_places':3,} D_delta = DecimalNumber(delta,**dn_kwargs) D_rou = DecimalNumber(rou,**dn_kwargs).shift(LEFT) D_move = DecimalNumber(move,**dn_kwargs).next_to(D_rou,DOWN) D_target = DecimalNumber(target,**dn_kwargs).next_to(D_move,DOWN) #######解析式-修改这里 《公式r》 就好####### r = lambda t: np.sin(D_rou.get_value()*t)+1 ############################################ par = lambda t: np.array([ (r(t))*np.cos(D_move.get_value()*t), (r(t))*np.sin(D_move.get_value()*t), 0]) #coordinate system & labels axes = Axes( x_range=[-0, 2*PI, PI/4], y_range=[-0.1, 2.5, 1], x_length=14, y_length=2 ).to_edge(UP) axes_label = axes.get_axis_labels('Time','Intensity') #polar plane polarPlane = PolarPlane( radius_max=2.0, azimuth_units="TAU radians", size=4, azimuth_label_font_size=24, radius_config={"font_size": 24}, ).add_coordinates().to_edge(DOWN+LEFT) #point track plane pointAxes = Axes( x_range=[0, track_end+track_end*0.3,1], y_range=[-0.5, 1], x_length=6, y_length=4 ).to_edge(UP).to_edge(DOWN+RIGHT) #更新函数 def Func_axes(): return axes.plot(r,color=PINK) def Func_polar(): return polarPlane.plot_polar_graph(r, [0, 2 * PI], color=ORANGE) def Func_para(): para = ParametricFunction( par, t_range = np.array([0, 3.14*2]), fill_opacity=0)\ .set_color(color=[RED,YELLOW,BLUE,RED]) return para def Func_para_with_messPoint(): para = ParametricFunction( par, t_range = np.array([0, 3.14*2]), fill_opacity=0)\ .set_color(color=[RED,YELLOW,BLUE,RED]) messPoint = Dot(pointAxes.coords_to_point(D_move.get_value(),para.get_y()),color=GREEN_B,radius=0.02) self.add(messPoint) return para axes_graph = Func_axes() polar_graph = Func_polar() para_graph = Func_para() #define messPoint messPoint = Dot(para_graph.get_center()) #定义updater_func表达式 axU = lambda mob: mob.become(Func_axes()) poU = lambda mob: mob.become(Func_polar()) paU = lambda mob:mob.become(Func_para().shift(DOWN+RIGHT*3)) paU_with_messPoint = lambda mob:mob.become(Func_para_with_messPoint().move_to(para_graph)) #添加updater axes_graph.add_updater(axU) polar_graph.add_updater(poU) para_graph.add_updater(paU) ################################################ ####################开始动画#################### ################################################ #显示坐标与坐标标签 group_axes = VGroup(axes,axes_label,axes_graph) group_polar = VGroup(polarPlane,polar_graph) self.add(D_rou,D_move) self.play(Write(group_axes),Write(group_polar),Write(para_graph)) self.play(ChangeDecimalToValue(D_rou,track_end),run_time=14,rate_func=linear) #左下角的图像消失,右下角的图像挪来左边 polar_graph.remove_updater(poU) self.play(FadeOut(polar_graph)) para_graph.remove_updater(paU) self.play(para_graph.animate.move_to(group_polar)) self.play(GrowFromCenter(pointAxes)) #开始扭扭~并且加点追踪 para_graph.add_updater(paU_with_messPoint) D_move.set_value(0) self.play(ChangeDecimalToValue(D_move,track_end),run_time=30,rate_func=linear) self.wait(1)
分类:
manim
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~