mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Began FilterOutHighPitch in fourier
This commit is contained in:
parent
5780998115
commit
c3cc3e1144
1 changed files with 234 additions and 36 deletions
|
@ -29,7 +29,23 @@ from mobject.svg_mobject import *
|
||||||
from mobject.tex_mobject import *
|
from mobject.tex_mobject import *
|
||||||
from topics.graph_scene import *
|
from topics.graph_scene import *
|
||||||
|
|
||||||
#revert_to_original_skipping_status
|
|
||||||
|
def get_fourier_transform(
|
||||||
|
func, t_min, t_max,
|
||||||
|
real_part = True,
|
||||||
|
use_almost_fourier = True,
|
||||||
|
):
|
||||||
|
# part = "real" if real_part else "imag"
|
||||||
|
trig = np.cos if real_part else np.sin
|
||||||
|
scalar = 1./(t_max - t_min) if use_almost_fourier else 1.0
|
||||||
|
def fourier_transform(f):
|
||||||
|
return scalar*scipy.integrate.quad(
|
||||||
|
lambda t : func(t)*trig(-TAU*f*t),
|
||||||
|
t_min, t_max
|
||||||
|
)[0]
|
||||||
|
return fourier_transform
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
class AddingPureFrequencies(PiCreatureScene):
|
class AddingPureFrequencies(PiCreatureScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
@ -811,27 +827,10 @@ class FourierMachineScene(Scene):
|
||||||
t_min = self.time_axes.x_min
|
t_min = self.time_axes.x_min
|
||||||
t_max = self.time_axes.x_max
|
t_max = self.time_axes.x_max
|
||||||
return self.frequency_axes.get_graph(
|
return self.frequency_axes.get_graph(
|
||||||
self.get_fourier_transform(func, t_min, t_max, **kwargs),
|
get_fourier_transform(func, t_min, t_max, **kwargs),
|
||||||
color = self.center_of_mass_color,
|
color = self.center_of_mass_color,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_fourier_transform(
|
|
||||||
self, func, t_min, t_max,
|
|
||||||
real_part = True,
|
|
||||||
use_almost_fourier = True,
|
|
||||||
):
|
|
||||||
part = "real" if real_part else "imag"
|
|
||||||
scalar = 1./(t_max - t_min) if use_almost_fourier else 1.0
|
|
||||||
def fourier_transform(f):
|
|
||||||
return scalar*scipy.integrate.quad(
|
|
||||||
lambda t : getattr(
|
|
||||||
func(t)*np.exp(complex(0, -TAU*f*t)),
|
|
||||||
part
|
|
||||||
),
|
|
||||||
t_min, t_max
|
|
||||||
)[0]
|
|
||||||
return fourier_transform
|
|
||||||
|
|
||||||
def get_polarized_mobject(self, mobject, freq = 1.0):
|
def get_polarized_mobject(self, mobject, freq = 1.0):
|
||||||
if not hasattr(self, "circle_plane"):
|
if not hasattr(self, "circle_plane"):
|
||||||
self.get_circle_plane()
|
self.get_circle_plane()
|
||||||
|
@ -1290,7 +1289,7 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
|
|
||||||
def draw_full_frequency_plot(self):
|
def draw_full_frequency_plot(self):
|
||||||
graph = self.graph
|
graph = self.graph
|
||||||
fourier_graph = self.get_fourier_transform_graph(graph)
|
fourier_graph = get_fourier_transform_graph(graph)
|
||||||
fourier_graph.save_state()
|
fourier_graph.save_state()
|
||||||
fourier_graph_update = self.get_fouier_graph_drawing_update_anim(
|
fourier_graph_update = self.get_fouier_graph_drawing_update_anim(
|
||||||
fourier_graph
|
fourier_graph
|
||||||
|
@ -1363,7 +1362,7 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
new_graph = self.get_cosine_wave(
|
new_graph = self.get_cosine_wave(
|
||||||
self.signal_frequency, shift_val = 0
|
self.signal_frequency, shift_val = 0
|
||||||
)
|
)
|
||||||
new_fourier_graph = self.get_fourier_transform_graph(new_graph)
|
new_fourier_graph = get_fourier_transform_graph(new_graph)
|
||||||
for mob in graph, time_axes, fourier_graph:
|
for mob in graph, time_axes, fourier_graph:
|
||||||
mob.save_state()
|
mob.save_state()
|
||||||
|
|
||||||
|
@ -1606,7 +1605,7 @@ class ShowLowerFrequency(DrawFrequencyPlot):
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
#Show fourier graph
|
#Show fourier graph
|
||||||
fourier_graph = self.get_fourier_transform_graph(graph)
|
fourier_graph = get_fourier_transform_graph(graph)
|
||||||
fourier_graph_update = self.get_fouier_graph_drawing_update_anim(
|
fourier_graph_update = self.get_fouier_graph_drawing_update_anim(
|
||||||
fourier_graph
|
fourier_graph
|
||||||
)
|
)
|
||||||
|
@ -1744,7 +1743,7 @@ class ShowLinearity(DrawFrequencyPlot):
|
||||||
self.center_of_mass_dot = dot
|
self.center_of_mass_dot = dot
|
||||||
self.generate_center_of_mass_dot_update_anim()
|
self.generate_center_of_mass_dot_update_anim()
|
||||||
|
|
||||||
fourier_graph = self.get_fourier_transform_graph(graph)
|
fourier_graph = get_fourier_transform_graph(graph)
|
||||||
fourier_graph_update = self.get_fouier_graph_drawing_update_anim(
|
fourier_graph_update = self.get_fouier_graph_drawing_update_anim(
|
||||||
fourier_graph
|
fourier_graph
|
||||||
)
|
)
|
||||||
|
@ -1831,16 +1830,16 @@ class ShowCommutativeDiagram(ShowLinearity):
|
||||||
ta_group.arrange_submobjects(DOWN, buff = MED_LARGE_BUFF)
|
ta_group.arrange_submobjects(DOWN, buff = MED_LARGE_BUFF)
|
||||||
ta_group.to_corner(UP+LEFT, buff = MED_SMALL_BUFF)
|
ta_group.to_corner(UP+LEFT, buff = MED_SMALL_BUFF)
|
||||||
|
|
||||||
freq_axes = Axes(**self.frequency_axes_config)
|
frequency_axes = Axes(**self.frequency_axes_config)
|
||||||
freq_axes.highlight(TEAL)
|
frequency_axes.highlight(TEAL)
|
||||||
freq_label = TextMobject("Frequency")
|
freq_label = TextMobject("Frequency")
|
||||||
freq_label.scale(self.text_scale_val)
|
freq_label.scale(self.text_scale_val)
|
||||||
freq_label.next_to(freq_axes.x_axis, DOWN, SMALL_BUFF, RIGHT)
|
freq_label.next_to(frequency_axes.x_axis, DOWN, SMALL_BUFF, RIGHT)
|
||||||
freq_axes.label = freq_label
|
frequency_axes.label = freq_label
|
||||||
freq_axes.add(freq_label)
|
frequency_axes.add(freq_label)
|
||||||
freq_axes.scale(0.8)
|
frequency_axes.scale(0.8)
|
||||||
fa_group = VGroup(
|
fa_group = VGroup(
|
||||||
freq_axes, freq_axes.deepcopy(), freq_axes.deepcopy()
|
frequency_axes, frequency_axes.deepcopy(), frequency_axes.deepcopy()
|
||||||
)
|
)
|
||||||
VGroup(ta_group[1], fa_group[1]).shift(MED_LARGE_BUFF*UP)
|
VGroup(ta_group[1], fa_group[1]).shift(MED_LARGE_BUFF*UP)
|
||||||
for ta, fa in zip(ta_group, fa_group):
|
for ta, fa in zip(ta_group, fa_group):
|
||||||
|
@ -1875,7 +1874,7 @@ class ShowCommutativeDiagram(ShowLinearity):
|
||||||
label.highlight(color)
|
label.highlight(color)
|
||||||
label.scale(0.75)
|
label.scale(0.75)
|
||||||
label.next_to(time_graph, UP, SMALL_BUFF)
|
label.next_to(time_graph, UP, SMALL_BUFF)
|
||||||
fourier = self.get_fourier_transform(
|
fourier = get_fourier_transform(
|
||||||
func, ta.x_min, 4*ta.x_max
|
func, ta.x_min, 4*ta.x_max
|
||||||
)
|
)
|
||||||
fourier_graph = fa.get_graph(fourier)
|
fourier_graph = fa.get_graph(fourier)
|
||||||
|
@ -2015,11 +2014,210 @@ class ShowCommutativeDiagram(ShowLinearity):
|
||||||
spike_rect.set_fill(YELLOW, 0.5)
|
spike_rect.set_fill(YELLOW, 0.5)
|
||||||
return spike_rect
|
return spike_rect
|
||||||
|
|
||||||
|
class BeforeGettingToTheFullMath(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
formula = TexMobject(
|
||||||
|
"\\hat{g}(f) = \\int_{-\\infty}^{\\infty}" + \
|
||||||
|
"g(t)e^{-2\\pi i f t}dt"
|
||||||
|
)
|
||||||
|
formula.next_to(self.teacher, UP+LEFT)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Write(formula),
|
||||||
|
self.teacher.change, "raise_right_hand",
|
||||||
|
self.get_student_changes(*["confused"]*3)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
ApplyMethod(
|
||||||
|
formula.next_to, SPACE_WIDTH*RIGHT, RIGHT,
|
||||||
|
path_arc = TAU/16,
|
||||||
|
rate_func = running_start,
|
||||||
|
),
|
||||||
|
self.get_student_changes(*["pondering"]*3)
|
||||||
|
)
|
||||||
|
self.teacher_says("Consider sound editing\\dots")
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
class FilterOutHighPitch(AddingPureFrequencies, ShowCommutativeDiagram):
|
||||||
|
def construct(self):
|
||||||
|
self.add_speaker()
|
||||||
|
self.play_sound()
|
||||||
|
self.show_intensity_vs_time_graph()
|
||||||
|
self.take_fourier_transform()
|
||||||
|
self.filter_out_high_pitch()
|
||||||
|
self.mention_inverse_transform()
|
||||||
|
|
||||||
|
def play_sound(self):
|
||||||
|
randy = self.pi_creature
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Succession(
|
||||||
|
ApplyMethod, randy.look_at, self.speaker,
|
||||||
|
Animation, randy,
|
||||||
|
ApplyMethod, randy.change, "telepath", randy,
|
||||||
|
Animation, randy,
|
||||||
|
Blink, randy,
|
||||||
|
Animation, randy, {"run_time" : 2},
|
||||||
|
),
|
||||||
|
*self.get_broadcast_anims(),
|
||||||
|
run_time = 7
|
||||||
|
)
|
||||||
|
self.play(randy.change, "angry", self.speaker)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def show_intensity_vs_time_graph(self):
|
||||||
|
randy = self.pi_creature
|
||||||
|
|
||||||
|
axes = Axes(
|
||||||
|
x_min = 0,
|
||||||
|
x_max = 12,
|
||||||
|
y_min = -6,
|
||||||
|
y_max = 6,
|
||||||
|
y_axis_config = {
|
||||||
|
"unit_size" : 0.15,
|
||||||
|
"tick_frequency" : 3,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
axes.set_stroke(width = 2)
|
||||||
|
axes.to_corner(UP+LEFT)
|
||||||
|
time_label = TextMobject("Time")
|
||||||
|
intensity_label = TextMobject("Intensity")
|
||||||
|
labels = VGroup(time_label, intensity_label)
|
||||||
|
labels.scale(0.75)
|
||||||
|
time_label.next_to(
|
||||||
|
axes.x_axis, DOWN,
|
||||||
|
aligned_edge = RIGHT,
|
||||||
|
buff = SMALL_BUFF
|
||||||
|
)
|
||||||
|
intensity_label.next_to(
|
||||||
|
axes.y_axis, RIGHT,
|
||||||
|
aligned_edge = UP,
|
||||||
|
buff = SMALL_BUFF
|
||||||
|
)
|
||||||
|
axes.labels = labels
|
||||||
|
|
||||||
|
func = lambda t : sum([
|
||||||
|
np.cos(TAU*f*t)
|
||||||
|
for f in 0.5, 0.7, 1.0, 1.2, 3.0,
|
||||||
|
])
|
||||||
|
graph = axes.get_graph(func)
|
||||||
|
graph.highlight(BLUE)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeIn(axes),
|
||||||
|
FadeIn(axes.labels),
|
||||||
|
randy.change, "pondering", axes,
|
||||||
|
ShowCreation(
|
||||||
|
graph, run_time = 4,
|
||||||
|
rate_func = bezier([0, 0, 1, 1])
|
||||||
|
),
|
||||||
|
*self.get_broadcast_anims(run_time = 6)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
self.time_axes = axes
|
||||||
|
self.time_graph = graph
|
||||||
|
|
||||||
|
def take_fourier_transform(self):
|
||||||
|
time_axes = self.time_axes
|
||||||
|
time_graph = self.time_graph
|
||||||
|
randy = self.pi_creature
|
||||||
|
speaker = self.speaker
|
||||||
|
|
||||||
|
frequency_axes = Axes(
|
||||||
|
x_min = 0,
|
||||||
|
x_max = 3.5,
|
||||||
|
x_axis_config = {"unit_size" : 3.5},
|
||||||
|
y_min = 0,
|
||||||
|
y_max = 1,
|
||||||
|
y_axis_config = {"unit_size" : 2},
|
||||||
|
)
|
||||||
|
frequency_axes.highlight(TEAL)
|
||||||
|
frequency_axes.next_to(time_axes, DOWN, LARGE_BUFF, LEFT)
|
||||||
|
freq_label = TextMobject("Frequency")
|
||||||
|
freq_label.scale(0.75)
|
||||||
|
freq_label.next_to(frequency_axes.x_axis, DOWN, MED_SMALL_BUFF, RIGHT)
|
||||||
|
frequency_axes.label = freq_label
|
||||||
|
|
||||||
|
fourier_func = get_fourier_transform(
|
||||||
|
time_graph.underlying_function,
|
||||||
|
t_min = 0, t_max = 30,
|
||||||
|
)
|
||||||
|
def alt_fourier_func(t):
|
||||||
|
bell = smooth(t)*0.3*np.exp(-0.8*(t-0.9)**2)
|
||||||
|
return bell + (smooth(t/3)+0.2)*fourier_func(t)
|
||||||
|
fourier_graph = frequency_axes.get_graph(
|
||||||
|
alt_fourier_func, num_graph_points = 150,
|
||||||
|
)
|
||||||
|
fourier_graph.highlight(RED)
|
||||||
|
frequency_axes.graph = fourier_graph
|
||||||
|
|
||||||
|
arrow = Arrow(time_graph, fourier_graph, color = WHITE)
|
||||||
|
ft_words = TextMobject("Fourier \\\\ transform")
|
||||||
|
ft_words.next_to(arrow, RIGHT)
|
||||||
|
|
||||||
|
spike_rect = self.get_spike_rect(frequency_axes, 3)
|
||||||
|
spike_rect.stretch(2, 0)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(time_axes.copy(), frequency_axes),
|
||||||
|
ReplacementTransform(time_graph.copy(), fourier_graph),
|
||||||
|
ReplacementTransform(time_axes.labels[0].copy(), freq_label),
|
||||||
|
GrowArrow(arrow),
|
||||||
|
Write(ft_words),
|
||||||
|
VGroup(randy, speaker).shift, SPACE_HEIGHT*DOWN,
|
||||||
|
)
|
||||||
|
self.remove(randy, speaker)
|
||||||
|
self.wait()
|
||||||
|
self.play(DrawBorderThenFill(spike_rect))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
self.frequency_axes = frequency_axes
|
||||||
|
self.fourier_graph = fourier_graph
|
||||||
|
self.spike_rect = spike_rect
|
||||||
|
|
||||||
|
def filter_out_high_pitch(self):
|
||||||
|
fourier_graph = self.fourier_graph
|
||||||
|
spike_rect = self.spike_rect
|
||||||
|
frequency_axes = self.frequency_axes
|
||||||
|
|
||||||
|
def filtered_func(f):
|
||||||
|
result = fourier_graph.underlying_function(f)
|
||||||
|
result *= np.clip(smooth(3-f), 0, 1)
|
||||||
|
return result
|
||||||
|
|
||||||
|
new_graph = frequency_axes.get_graph(
|
||||||
|
filtered_func, num_graph_points = 200
|
||||||
|
)
|
||||||
|
new_graph.highlight(RED)
|
||||||
|
|
||||||
|
self.play(spike_rect.stretch, 4)
|
||||||
|
self.play(
|
||||||
|
Transform(fourier_graph, new_graph),
|
||||||
|
spike_rect.stretch, 0.01, {
|
||||||
|
"about_point" : frequency_axes.coords_to_point(0, 0)
|
||||||
|
},
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def mention_inverse_transform(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
def get_broadcast_anims(self, run_time = 7, **kwargs):
|
||||||
|
return [
|
||||||
|
self.get_broadcast_animation(
|
||||||
|
n_circles = n,
|
||||||
|
run_time = run_time,
|
||||||
|
big_radius = 7,
|
||||||
|
start_stroke_width = 5,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
for n in 5, 7, 10, 12
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue