mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
More scenes for ode1
This commit is contained in:
parent
9a452f3fee
commit
caf41f43d9
4 changed files with 563 additions and 50 deletions
|
@ -17,7 +17,8 @@ ALL_SCENE_CLASSES = [
|
||||||
SmallAngleApproximationTex,
|
SmallAngleApproximationTex,
|
||||||
VeryLowAnglePendulum,
|
VeryLowAnglePendulum,
|
||||||
FormulasAreLies,
|
FormulasAreLies,
|
||||||
FollowThisThread,
|
TourOfDifferentialEquations,
|
||||||
|
# FollowThisThread,
|
||||||
StrogatzQuote,
|
StrogatzQuote,
|
||||||
# Something...
|
# Something...
|
||||||
ShowGravityAcceleration,
|
ShowGravityAcceleration,
|
||||||
|
@ -40,6 +41,11 @@ ALL_SCENE_CLASSES = [
|
||||||
FromODEToVectorField,
|
FromODEToVectorField,
|
||||||
LorenzVectorField,
|
LorenzVectorField,
|
||||||
ThreeBodiesInSpace,
|
ThreeBodiesInSpace,
|
||||||
|
AltThreeBodiesInSpace,
|
||||||
ThreeBodySymbols,
|
ThreeBodySymbols,
|
||||||
AskAboutActuallySolving,
|
AskAboutActuallySolving,
|
||||||
|
WriteODESolvingCode,
|
||||||
|
TakeManyTinySteps,
|
||||||
|
InaccurateComputation,
|
||||||
|
HungerForExactness,
|
||||||
]
|
]
|
||||||
|
|
|
@ -1113,3 +1113,127 @@ class TweakMuInVectorField(ShowPendulumPhaseFlow):
|
||||||
)
|
)
|
||||||
self.add(animated_stream_lines)
|
self.add(animated_stream_lines)
|
||||||
self.wait(self.flow_time)
|
self.wait(self.flow_time)
|
||||||
|
|
||||||
|
|
||||||
|
class TakeManyTinySteps(IntroduceVectorField):
|
||||||
|
CONFIG = {
|
||||||
|
"initial_theta": 60 * DEGREES,
|
||||||
|
"initial_theta_dot": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.initialize_plane()
|
||||||
|
self.initialize_vector_field()
|
||||||
|
field = self.vector_field
|
||||||
|
field.set_opacity(0.35)
|
||||||
|
self.add(self.plane, field)
|
||||||
|
|
||||||
|
self.take_many_time_steps()
|
||||||
|
|
||||||
|
def take_many_time_steps(self):
|
||||||
|
delta_t_tracker = ValueTracker(0.5)
|
||||||
|
get_delta_t = delta_t_tracker.get_value
|
||||||
|
|
||||||
|
time_tracker = ValueTracker(10)
|
||||||
|
get_t = time_tracker.get_value
|
||||||
|
|
||||||
|
traj = always_redraw(
|
||||||
|
lambda: self.get_time_step_trajectory(
|
||||||
|
get_delta_t(), get_t()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
vectors = always_redraw(
|
||||||
|
lambda: self.get_path_vectors(
|
||||||
|
get_delta_t(), get_t()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
t_label, dt_label = labels = VGroup(*[
|
||||||
|
VGroup(
|
||||||
|
TexMobject("{} = ".format(s)),
|
||||||
|
DecimalNumber(0)
|
||||||
|
).arrange(RIGHT, aligned_edge=DOWN)
|
||||||
|
for s in ("t", "{\\Delta t}")
|
||||||
|
])
|
||||||
|
init_labels = VGroup(
|
||||||
|
TexMobject(
|
||||||
|
"\\theta_0", "= \\pi / 3",
|
||||||
|
tex_to_color_map={"\\theta": BLUE},
|
||||||
|
),
|
||||||
|
TexMobject(
|
||||||
|
"{\\dot\\theta}_0 = 0",
|
||||||
|
tex_to_color_map={"{\\dot\\theta}": YELLOW},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for group in labels, init_labels:
|
||||||
|
for label in group:
|
||||||
|
label.scale(1.25)
|
||||||
|
label.add_background_rectangle()
|
||||||
|
group.arrange(DOWN)
|
||||||
|
group.shift(FRAME_WIDTH * RIGHT / 4)
|
||||||
|
labels.to_edge(UP)
|
||||||
|
init_labels.shift(2 * DOWN)
|
||||||
|
|
||||||
|
dt_label[-1].add_updater(
|
||||||
|
lambda d: d.set_value(get_delta_t())
|
||||||
|
)
|
||||||
|
t_label[-1].add_updater(
|
||||||
|
lambda d: d.set_value(
|
||||||
|
int(get_t() / get_delta_t()) * get_delta_t()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add(traj, vectors, init_labels, labels)
|
||||||
|
time_tracker.set_value(0)
|
||||||
|
self.play(
|
||||||
|
time_tracker.set_value, 10,
|
||||||
|
run_time=5,
|
||||||
|
rate_func=linear,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
t_label[-1].clear_updaters()
|
||||||
|
self.play(
|
||||||
|
delta_t_tracker.set_value, 0.01,
|
||||||
|
run_time=7,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
#
|
||||||
|
def get_time_step_points(self, delta_t, total_time):
|
||||||
|
plane = self.plane
|
||||||
|
field = self.vector_field
|
||||||
|
curr_point = plane.coords_to_point(
|
||||||
|
self.initial_theta,
|
||||||
|
self.initial_theta_dot,
|
||||||
|
)
|
||||||
|
points = [curr_point]
|
||||||
|
t = 0
|
||||||
|
while t < total_time:
|
||||||
|
new_point = curr_point + field.func(curr_point) * delta_t
|
||||||
|
points.append(new_point)
|
||||||
|
curr_point = new_point
|
||||||
|
t += delta_t
|
||||||
|
return points
|
||||||
|
|
||||||
|
def get_time_step_trajectory(self, delta_t, total_time):
|
||||||
|
traj = VMobject()
|
||||||
|
traj.set_points_as_corners(
|
||||||
|
self.get_time_step_points(delta_t, total_time)
|
||||||
|
)
|
||||||
|
traj.set_stroke(WHITE, 2)
|
||||||
|
return traj
|
||||||
|
|
||||||
|
def get_path_vectors(self, delta_t, total_time):
|
||||||
|
corners = self.get_time_step_points(
|
||||||
|
delta_t, total_time
|
||||||
|
)
|
||||||
|
result = VGroup()
|
||||||
|
for a1, a2 in zip(corners, corners[1:]):
|
||||||
|
vector = Arrow(
|
||||||
|
a1, a2, buff=0,
|
||||||
|
)
|
||||||
|
vector.match_style(
|
||||||
|
self.vector_field.get_vector(a1)
|
||||||
|
)
|
||||||
|
result.add(vector)
|
||||||
|
return result
|
||||||
|
|
|
@ -103,6 +103,11 @@ class FormulasAreLies(PiCreatureScene):
|
||||||
return You().flip().to_corner(DR)
|
return You().flip().to_corner(DR)
|
||||||
|
|
||||||
|
|
||||||
|
# class TourOfDifferentialEquations(Scene):
|
||||||
|
# def construct(self):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
|
||||||
class ProveTeacherWrong(TeacherStudentsScene):
|
class ProveTeacherWrong(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
tex_config = {
|
tex_config = {
|
||||||
|
@ -197,15 +202,183 @@ class ProveTeacherWrong(TeacherStudentsScene):
|
||||||
self.wait(8)
|
self.wait(8)
|
||||||
|
|
||||||
|
|
||||||
class AskAboutActuallySolving(Scene):
|
class AskAboutActuallySolving(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
ode = get_ode()
|
ode = get_ode()
|
||||||
ode.to_corner(UL)
|
ode.to_corner(UL)
|
||||||
|
self.add(ode)
|
||||||
morty = self.teacher
|
morty = self.teacher
|
||||||
|
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"Yeah, yeah, but how do\\\\"
|
"Yeah yeah, but how do\\\\"
|
||||||
"you acutally \\emph{solve} it?",
|
"you acutally \\emph{solve} it?",
|
||||||
|
student_index=1,
|
||||||
target_mode="sassy",
|
target_mode="sassy",
|
||||||
added_anims=[morty.change, "thinking"],
|
added_anims=[morty.change, "thinking"],
|
||||||
)
|
)
|
||||||
|
self.change_student_modes(
|
||||||
|
"confused", "sassy", "confused",
|
||||||
|
look_at_arg=ode,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.teacher_says(
|
||||||
|
"What do you mean\\\\ by ``solve''?",
|
||||||
|
target_mode="speaking",
|
||||||
|
added_anims=[self.get_student_changes(
|
||||||
|
*3 * ["erm"]
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
self.play(self.students[1].change, "angry")
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
|
||||||
|
class HungerForExactness(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
students = self.students
|
||||||
|
you = students[2]
|
||||||
|
teacher = self.teacher
|
||||||
|
|
||||||
|
ode = get_ode()
|
||||||
|
ode.to_corner(UL)
|
||||||
|
left_part = ode[:5]
|
||||||
|
friction_part = ode[5:11]
|
||||||
|
right_part = ode[11:]
|
||||||
|
self.add(ode)
|
||||||
|
frictionless_group = VGroup(left_part, right_part)
|
||||||
|
|
||||||
|
proposed_solution = TexMobject(
|
||||||
|
"\\theta_0\\cos((\\sqrt{g/L})t)e^{-\\mu t}"
|
||||||
|
)
|
||||||
|
proposed_solution.next_to(
|
||||||
|
you.get_corner(UL), UP, buff=0.7
|
||||||
|
)
|
||||||
|
proposed_solution_rect = SurroundingRectangle(
|
||||||
|
proposed_solution, buff=MED_SMALL_BUFF,
|
||||||
|
)
|
||||||
|
proposed_solution_rect.set_color(BLUE)
|
||||||
|
proposed_solution_rect.round_corners()
|
||||||
|
|
||||||
|
solution_p1 = TexMobject(
|
||||||
|
"""
|
||||||
|
\\theta(t) = 2\\text{am}\\left(
|
||||||
|
\\frac{\\sqrt{2g + Lc_1} (t + c_2)}{2\\sqrt{L}},
|
||||||
|
\\frac{4g}{2g + Lc_1}
|
||||||
|
\\right)
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
solution_p1.to_corner(UL)
|
||||||
|
solution_p2 = TexMobject(
|
||||||
|
"c_1, c_2 = \\text{Constants depending on initial conditions}"
|
||||||
|
)
|
||||||
|
solution_p2.set_color(LIGHT_GREY)
|
||||||
|
solution_p2.scale(0.75)
|
||||||
|
solution_p3 = TexMobject(
|
||||||
|
"""
|
||||||
|
\\text{am}(u, k) =
|
||||||
|
\\int_0^u \\text{dn}(v, k)\\,dv
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
solution_p3.name = TextMobject(
|
||||||
|
"(Jacobi amplitude function)"
|
||||||
|
)
|
||||||
|
solution_p4 = TexMobject(
|
||||||
|
"""
|
||||||
|
\\text{dn}(u, k) =
|
||||||
|
\\sqrt{1 - k^2 \\sin^2(\\phi)}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
solution_p4.name = TextMobject(
|
||||||
|
"(Jacobi elliptic function)"
|
||||||
|
)
|
||||||
|
solution_p5 = TextMobject("Where $\\phi$ satisfies")
|
||||||
|
solution_p6 = TexMobject(
|
||||||
|
"""
|
||||||
|
u = \\int_0^\\phi \\frac{dt}{\\sqrt{1 - k^2 \\sin^2(t)}}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
solution = VGroup(
|
||||||
|
solution_p1,
|
||||||
|
solution_p2,
|
||||||
|
solution_p3,
|
||||||
|
solution_p4,
|
||||||
|
solution_p5,
|
||||||
|
solution_p6,
|
||||||
|
)
|
||||||
|
solution.arrange(DOWN)
|
||||||
|
solution.scale(0.7)
|
||||||
|
solution.to_corner(UL, buff=MED_SMALL_BUFF)
|
||||||
|
solution.set_stroke(width=0, background=True)
|
||||||
|
|
||||||
|
solution.remove(solution_p2)
|
||||||
|
solution_p1.add(solution_p2)
|
||||||
|
solution.remove(solution_p5)
|
||||||
|
solution_p6.add(solution_p5)
|
||||||
|
|
||||||
|
for part in [solution_p3, solution_p4]:
|
||||||
|
part.name.scale(0.7 * 0.7)
|
||||||
|
part.name.set_color(LIGHT_GREY)
|
||||||
|
part.name.next_to(part, RIGHT)
|
||||||
|
part.add(part.name)
|
||||||
|
|
||||||
|
self.student_says(
|
||||||
|
"Right, but like,\\\\"
|
||||||
|
"what \\emph{is} $\\theta(t)$?",
|
||||||
|
target_mode="sassy",
|
||||||
|
added_anims=[teacher.change, "guilty"],
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
FadeInFromDown(proposed_solution),
|
||||||
|
RemovePiCreatureBubble(
|
||||||
|
you,
|
||||||
|
target_mode="raise_left_hand",
|
||||||
|
look_at_arg=proposed_solution,
|
||||||
|
),
|
||||||
|
teacher.change, "pondering",
|
||||||
|
students[0].change, "pondering",
|
||||||
|
students[1].change, "hesitant",
|
||||||
|
)
|
||||||
|
self.play(ShowCreation(proposed_solution_rect))
|
||||||
|
self.play(
|
||||||
|
proposed_solution.shift, 3 * RIGHT,
|
||||||
|
proposed_solution_rect.shift, 3 * RIGHT,
|
||||||
|
you.change, "raise_right_hand", teacher.eyes,
|
||||||
|
)
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeOut(proposed_solution),
|
||||||
|
FadeOut(proposed_solution_rect),
|
||||||
|
ode.move_to, self.hold_up_spot, DOWN,
|
||||||
|
ode.shift, LEFT,
|
||||||
|
teacher.change, "raise_right_hand",
|
||||||
|
self.get_student_changes(*3 * ["pondering"])
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
ode.save_state()
|
||||||
|
self.play(
|
||||||
|
left_part.move_to, friction_part, RIGHT,
|
||||||
|
left_part.match_y, left_part,
|
||||||
|
friction_part.to_corner, DR,
|
||||||
|
friction_part.fade, 0.5,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
modes = ["erm", "sad", "sad", "horrified"]
|
||||||
|
for part, mode in zip(solution, modes):
|
||||||
|
self.play(
|
||||||
|
FadeInFrom(part, UP),
|
||||||
|
self.get_student_changes(
|
||||||
|
*3 * [mode],
|
||||||
|
look_at_arg=part,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.wait(3)
|
||||||
|
self.play(
|
||||||
|
FadeOutAndShift(solution, 2 * LEFT),
|
||||||
|
Restore(ode),
|
||||||
|
self.get_student_changes(*3 * ["sick"])
|
||||||
|
)
|
||||||
|
self.wait(3)
|
||||||
|
|
|
@ -39,28 +39,37 @@ class VectorFieldTest(Scene):
|
||||||
self.wait(10)
|
self.wait(10)
|
||||||
|
|
||||||
|
|
||||||
class FollowThisThread(Scene):
|
class TourOfDifferentialEquations(MovingCameraScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"screen_rect_style": {
|
"screen_rect_style": {
|
||||||
"stroke_width": 2,
|
"stroke_width": 2,
|
||||||
"stroke_color": WHITE,
|
"stroke_color": WHITE,
|
||||||
"fill_opacity": 1,
|
"fill_opacity": 1,
|
||||||
"fill_color": DARKER_GREY,
|
"fill_color": BLACK,
|
||||||
}
|
},
|
||||||
|
"camera_config": {"background_color": DARKER_GREY},
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
self.add_title()
|
||||||
self.show_thumbnails()
|
self.show_thumbnails()
|
||||||
self.show_words()
|
# self.show_words()
|
||||||
|
|
||||||
|
def add_title(self):
|
||||||
|
title = TextMobject(
|
||||||
|
"A Tourist's Guide \\\\to Differential\\\\Equations"
|
||||||
|
)
|
||||||
|
title.scale(1.5)
|
||||||
|
title.to_corner(UR)
|
||||||
|
self.add(title)
|
||||||
|
|
||||||
def show_thumbnails(self):
|
def show_thumbnails(self):
|
||||||
# TODO, replace each of these with a picture?
|
thumbnails = self.thumbnails = Group(
|
||||||
thumbnails = self.thumbnails = VGroup(
|
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||||
ScreenRectangle(**self.screen_rect_style),
|
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||||
ScreenRectangle(**self.screen_rect_style),
|
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||||
ScreenRectangle(**self.screen_rect_style),
|
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||||
ScreenRectangle(**self.screen_rect_style),
|
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||||
ScreenRectangle(**self.screen_rect_style),
|
|
||||||
)
|
)
|
||||||
n = len(thumbnails)
|
n = len(thumbnails)
|
||||||
thumbnails.set_height(1.5)
|
thumbnails.set_height(1.5)
|
||||||
|
@ -71,8 +80,16 @@ class FollowThisThread(Scene):
|
||||||
[-3, -3, 0],
|
[-3, -3, 0],
|
||||||
[5, -3, 0],
|
[5, -3, 0],
|
||||||
])
|
])
|
||||||
|
line.shift(MED_SMALL_BUFF * LEFT)
|
||||||
for thumbnail, a in zip(thumbnails, np.linspace(0, 1, n)):
|
for thumbnail, a in zip(thumbnails, np.linspace(0, 1, n)):
|
||||||
thumbnail.move_to(line.point_from_proportion(a))
|
thumbnail.move_to(line.point_from_proportion(a))
|
||||||
|
dots = TexMobject("\\dots")
|
||||||
|
dots.next_to(thumbnails[-1], RIGHT)
|
||||||
|
|
||||||
|
self.add_heat_preview(thumbnails[1])
|
||||||
|
self.add_fourier_series(thumbnails[2])
|
||||||
|
self.add_matrix_exponent(thumbnails[3])
|
||||||
|
self.add_laplace_symbol(thumbnails[4])
|
||||||
|
|
||||||
self.play(
|
self.play(
|
||||||
ShowCreation(
|
ShowCreation(
|
||||||
|
@ -91,6 +108,14 @@ class FollowThisThread(Scene):
|
||||||
], lag_ratio=1),
|
], lag_ratio=1),
|
||||||
run_time=5
|
run_time=5
|
||||||
)
|
)
|
||||||
|
self.play(Write(dots))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
self.camera_frame.replace,
|
||||||
|
thumbnails[0],
|
||||||
|
run_time=3,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
def show_words(self):
|
def show_words(self):
|
||||||
words = VGroup(
|
words = VGroup(
|
||||||
|
@ -123,6 +148,71 @@ class FollowThisThread(Scene):
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
#
|
||||||
|
def add_heat_preview(self, thumbnail):
|
||||||
|
image = ImageMobject("HeatSurfaceExample")
|
||||||
|
image.replace(thumbnail)
|
||||||
|
thumbnail.add(image)
|
||||||
|
|
||||||
|
def add_matrix_exponent(self, thumbnail):
|
||||||
|
matrix = IntegerMatrix(
|
||||||
|
[[3, 1], [4, 1]],
|
||||||
|
v_buff=MED_LARGE_BUFF,
|
||||||
|
h_buff=MED_LARGE_BUFF,
|
||||||
|
bracket_h_buff=SMALL_BUFF,
|
||||||
|
bracket_v_buff=SMALL_BUFF,
|
||||||
|
)
|
||||||
|
e = TexMobject("e")
|
||||||
|
t = TexMobject("t")
|
||||||
|
t.scale(1.5)
|
||||||
|
t.next_to(matrix, RIGHT, SMALL_BUFF)
|
||||||
|
e.scale(2)
|
||||||
|
e.move_to(matrix.get_corner(DL), UR)
|
||||||
|
group = VGroup(e, matrix, t)
|
||||||
|
group.set_height(0.7 * thumbnail.get_height())
|
||||||
|
randy = Randolph(mode="confused", height=0.75)
|
||||||
|
randy.next_to(group, LEFT, aligned_edge=DOWN)
|
||||||
|
randy.look_at(matrix)
|
||||||
|
group.add(randy)
|
||||||
|
group.move_to(thumbnail)
|
||||||
|
thumbnail.add(group)
|
||||||
|
|
||||||
|
def add_fourier_series(self, thumbnail):
|
||||||
|
colors = [BLUE, GREEN, YELLOW, RED, RED_E, PINK]
|
||||||
|
|
||||||
|
waves = VGroup(*[
|
||||||
|
self.get_square_wave_approx(N, color)
|
||||||
|
for N, color in enumerate(colors)
|
||||||
|
])
|
||||||
|
waves.set_stroke(width=1.5)
|
||||||
|
waves.replace(thumbnail, stretch=True)
|
||||||
|
waves.scale(0.8)
|
||||||
|
waves.move_to(thumbnail)
|
||||||
|
thumbnail.add(waves)
|
||||||
|
|
||||||
|
def get_square_wave_approx(self, N, color):
|
||||||
|
return FunctionGraph(
|
||||||
|
lambda x: sum([
|
||||||
|
(1 / n) * np.sin(n * PI * x)
|
||||||
|
for n in range(1, 2 * N + 3, 2)
|
||||||
|
]),
|
||||||
|
x_min=0,
|
||||||
|
x_max=2,
|
||||||
|
color=color
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_laplace_symbol(self, thumbnail):
|
||||||
|
mob = TexMobject(
|
||||||
|
"\\mathcal{L}\\left\\{f(t)\\right\\}"
|
||||||
|
)
|
||||||
|
mob.set_width(0.8 * thumbnail.get_width())
|
||||||
|
mob.move_to(thumbnail)
|
||||||
|
thumbnail.add(mob)
|
||||||
|
|
||||||
|
|
||||||
|
class HeatEquationPreview(ExternallyAnimatedScene):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ShowGravityAcceleration(Scene):
|
class ShowGravityAcceleration(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -395,15 +485,7 @@ class DefineODE(Scene):
|
||||||
de_word = TextMobject("Differential", "Equation")
|
de_word = TextMobject("Differential", "Equation")
|
||||||
de_word.to_edge(UP)
|
de_word.to_edge(UP)
|
||||||
|
|
||||||
equation = TexMobject(
|
equation = get_ode()
|
||||||
"\\ddot \\theta({t})", "=",
|
|
||||||
"-\\mu \\dot \\theta({t})",
|
|
||||||
"-{g \\over L} \\sin\\big(\\theta({t})\\big)",
|
|
||||||
tex_to_color_map={
|
|
||||||
"\\theta": BLUE,
|
|
||||||
"{t}": WHITE
|
|
||||||
}
|
|
||||||
)
|
|
||||||
equation.next_to(de_word, DOWN)
|
equation.next_to(de_word, DOWN)
|
||||||
thetas = equation.get_parts_by_tex("\\theta")
|
thetas = equation.get_parts_by_tex("\\theta")
|
||||||
|
|
||||||
|
@ -475,11 +557,18 @@ class DefineODE(Scene):
|
||||||
)
|
)
|
||||||
|
|
||||||
tex_config = {
|
tex_config = {
|
||||||
"tex_to_color_map": {"\\theta": BLUE},
|
"tex_to_color_map": {
|
||||||
|
"{\\theta}": BLUE,
|
||||||
|
"{\\dot\\theta}": YELLOW,
|
||||||
|
"{\\ddot\\theta}": RED,
|
||||||
|
},
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
}
|
}
|
||||||
theta, d_theta, dd_theta = [
|
theta, d_theta, dd_theta = [
|
||||||
TexMobject(s + "\\theta(t)", **tex_config)
|
TexMobject(
|
||||||
|
"{" + s + "\\theta}(t)",
|
||||||
|
**tex_config
|
||||||
|
)
|
||||||
for s in ("", "\\dot", "\\ddot")
|
for s in ("", "\\dot", "\\ddot")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -500,7 +589,7 @@ class DefineODE(Scene):
|
||||||
return DashedLine(
|
return DashedLine(
|
||||||
x_point, point,
|
x_point, point,
|
||||||
dash_length=0.025,
|
dash_length=0.025,
|
||||||
stroke_color=WHITE,
|
stroke_color=BLUE,
|
||||||
stroke_width=2,
|
stroke_width=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -545,7 +634,7 @@ class DefineODE(Scene):
|
||||||
thetas = VGroup(theta, d_theta, dd_theta)
|
thetas = VGroup(theta, d_theta, dd_theta)
|
||||||
|
|
||||||
words = VGroup(
|
words = VGroup(
|
||||||
TextMobject("= Height"),
|
TextMobject("= Height").set_color(BLUE),
|
||||||
TextMobject("= Slope").set_color(YELLOW),
|
TextMobject("= Slope").set_color(YELLOW),
|
||||||
TextMobject("= ``Curvature''").set_color(RED),
|
TextMobject("= ``Curvature''").set_color(RED),
|
||||||
)
|
)
|
||||||
|
@ -887,7 +976,8 @@ class LorenzVectorField(ExternallyAnimatedScene):
|
||||||
|
|
||||||
class ThreeBodiesInSpace(SpecialThreeDScene):
|
class ThreeBodiesInSpace(SpecialThreeDScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"masses": [1, 2, 3],
|
"masses": [1, 6, 3],
|
||||||
|
"colors": [RED_E, GREEN_E, BLUE_E],
|
||||||
"G": 0.5,
|
"G": 0.5,
|
||||||
"play_time": 60,
|
"play_time": 60,
|
||||||
}
|
}
|
||||||
|
@ -900,26 +990,48 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
||||||
|
|
||||||
def add_axes(self):
|
def add_axes(self):
|
||||||
axes = self.axes = self.get_axes()
|
axes = self.axes = self.get_axes()
|
||||||
|
axes.set_stroke(width=0.5)
|
||||||
self.add(axes)
|
self.add(axes)
|
||||||
|
|
||||||
def add_bodies(self):
|
def add_bodies(self):
|
||||||
|
masses = self.masses
|
||||||
|
colors = self.colors
|
||||||
|
|
||||||
bodies = self.bodies = VGroup()
|
bodies = self.bodies = VGroup()
|
||||||
velocity_vectors = VGroup()
|
velocity_vectors = VGroup()
|
||||||
|
|
||||||
for mass in self.masses:
|
centers = [
|
||||||
body = self.get_sphere(
|
np.dot(
|
||||||
checkerboard_colors=[DARK_BROWN, DARK_BROWN],
|
4 * (np.random.random(3) - 0.5),
|
||||||
stroke_width=0.1,
|
|
||||||
)
|
|
||||||
body.mass = mass
|
|
||||||
body.set_width(0.2 * mass)
|
|
||||||
|
|
||||||
point = np.dot(
|
|
||||||
2 * (np.random.random(3) - 0.5),
|
|
||||||
[RIGHT, UP, OUT]
|
[RIGHT, UP, OUT]
|
||||||
)
|
)
|
||||||
velocity = normalize(np.cross(point, OUT))
|
for x in range(len(masses))
|
||||||
body.move_to(point)
|
]
|
||||||
|
|
||||||
|
for mass, color, center in zip(masses, colors, centers):
|
||||||
|
body = self.get_sphere(
|
||||||
|
checkerboard_colors=[
|
||||||
|
color, color
|
||||||
|
],
|
||||||
|
color=color,
|
||||||
|
stroke_width=0.1,
|
||||||
|
)
|
||||||
|
body.set_opacity(0.75)
|
||||||
|
body.mass = mass
|
||||||
|
body.set_width(0.15 * np.sqrt(mass))
|
||||||
|
|
||||||
|
body.point = center
|
||||||
|
body.move_to(center)
|
||||||
|
|
||||||
|
to_others = [
|
||||||
|
center - center2
|
||||||
|
for center2 in centers
|
||||||
|
]
|
||||||
|
velocity = 0.2 * mass * normalize(np.cross(*filter(
|
||||||
|
lambda diff: get_norm(diff) > 0,
|
||||||
|
to_others
|
||||||
|
)))
|
||||||
|
|
||||||
body.velocity = velocity
|
body.velocity = velocity
|
||||||
body.add_updater(self.update_body)
|
body.add_updater(self.update_body)
|
||||||
|
|
||||||
|
@ -946,27 +1058,28 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
||||||
|
|
||||||
def add_trajectories(self):
|
def add_trajectories(self):
|
||||||
def update_trajectory(traj, dt):
|
def update_trajectory(traj, dt):
|
||||||
new_point = traj.body.get_center()
|
new_point = traj.body.point
|
||||||
if get_norm(new_point - traj.points[-1]) > 0.01:
|
if get_norm(new_point - traj.points[-1]) > 0.01:
|
||||||
traj.add_smooth_curve_to(new_point)
|
traj.add_smooth_curve_to(new_point)
|
||||||
|
|
||||||
for body in self.bodies:
|
for body in self.bodies:
|
||||||
traj = VMobject()
|
traj = VMobject()
|
||||||
traj.body = body
|
traj.body = body
|
||||||
traj.start_new_path(body.get_center())
|
traj.start_new_path(body.point)
|
||||||
traj.set_stroke(WHITE, 1)
|
traj.set_stroke(body.color, 1, opacity=0.75)
|
||||||
traj.add_updater(update_trajectory)
|
traj.add_updater(update_trajectory)
|
||||||
self.add(traj, body)
|
self.add(traj, body)
|
||||||
|
|
||||||
def let_play(self):
|
def let_play(self):
|
||||||
self.move_camera(
|
self.set_camera_orientation(
|
||||||
phi=70 * DEGREES,
|
phi=70 * DEGREES,
|
||||||
theta=-110 * DEGREES,
|
theta=-110 * DEGREES,
|
||||||
run_time=3,
|
|
||||||
)
|
)
|
||||||
self.begin_ambient_camera_rotation()
|
self.begin_ambient_camera_rotation()
|
||||||
for x in range(6):
|
# Break it up to see partial files as
|
||||||
self.wait(self.play_time / 6)
|
# it's rendered
|
||||||
|
for x in range(int(self.play_time)):
|
||||||
|
self.wait()
|
||||||
|
|
||||||
#
|
#
|
||||||
def get_velocity_vector_mob(self, body):
|
def get_velocity_vector_mob(self, body):
|
||||||
|
@ -994,13 +1107,110 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
||||||
for body2 in self.bodies:
|
for body2 in self.bodies:
|
||||||
if body2 is body:
|
if body2 is body:
|
||||||
continue
|
continue
|
||||||
diff = body2.get_center() - body.get_center()
|
diff = body2.point - body.point
|
||||||
m2 = body2.mass
|
m2 = body2.mass
|
||||||
R = get_norm(diff)
|
R = get_norm(diff)
|
||||||
acceleration += G * m2 * diff / (R**3)
|
acceleration += G * m2 * diff / (R**3)
|
||||||
|
|
||||||
body.shift(body.velocity * dt)
|
num_mid_steps = 100
|
||||||
body.velocity += acceleration * dt
|
for x in range(num_mid_steps):
|
||||||
|
body.point += body.velocity * dt / num_mid_steps
|
||||||
|
body.velocity += acceleration * dt / num_mid_steps
|
||||||
|
body.move_to(body.point)
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
class AltThreeBodiesInSpace(ThreeBodiesInSpace):
|
||||||
|
CONFIG = {
|
||||||
|
"random_seed": 6,
|
||||||
|
"masses": [1, 2, 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DefineODECopy(DefineODE):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class WriteODESolvingCode(ExternallyAnimatedScene):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InaccurateComputation(Scene):
|
||||||
|
def construct(self):
|
||||||
|
h_line = DashedLine(LEFT_SIDE, RIGHT_SIDE)
|
||||||
|
h_line.to_edge(UP, buff=1.5)
|
||||||
|
words = VGroup(
|
||||||
|
TextMobject("Real number"),
|
||||||
|
TextMobject("IEEE 754\\\\representation"),
|
||||||
|
TextMobject("Error"),
|
||||||
|
)
|
||||||
|
for i, word in zip([-1, 0, 1], words):
|
||||||
|
word.next_to(h_line, UP)
|
||||||
|
word.shift(i * FRAME_WIDTH * RIGHT / 3)
|
||||||
|
|
||||||
|
lines = VGroup(*[
|
||||||
|
DashedLine(TOP, BOTTOM)
|
||||||
|
for x in range(4)
|
||||||
|
])
|
||||||
|
lines.arrange(RIGHT)
|
||||||
|
lines.stretch_to_fit_width(FRAME_WIDTH)
|
||||||
|
|
||||||
|
self.add(h_line, lines[1:-1], words)
|
||||||
|
|
||||||
|
numbers = VGroup(
|
||||||
|
TexMobject("\\pi").scale(2),
|
||||||
|
TexMobject("e^{\\sqrt{163}\\pi}").scale(1.5),
|
||||||
|
)
|
||||||
|
numbers.set_color(YELLOW)
|
||||||
|
numbers.set_stroke(width=0, background=True)
|
||||||
|
|
||||||
|
bit_strings = VGroup(
|
||||||
|
TexMobject(
|
||||||
|
"01000000",
|
||||||
|
"01001001",
|
||||||
|
"00001111",
|
||||||
|
"11011011",
|
||||||
|
),
|
||||||
|
TexMobject(
|
||||||
|
"01011100",
|
||||||
|
"01101001",
|
||||||
|
"00101110",
|
||||||
|
"00011001",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for mob in bit_strings:
|
||||||
|
mob.arrange(DOWN, buff=SMALL_BUFF)
|
||||||
|
for word in mob:
|
||||||
|
for submob, bit in zip(word, word.get_tex_string()):
|
||||||
|
if bit == "0":
|
||||||
|
submob.set_color(LIGHT_GREY)
|
||||||
|
errors = VGroup(
|
||||||
|
TexMobject(
|
||||||
|
"\\approx 8.7422 \\times 10^{-8}"
|
||||||
|
),
|
||||||
|
TexMobject(
|
||||||
|
"\\approx 5{,}289{,}803{,}032.00",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
errors.set_color(RED)
|
||||||
|
|
||||||
|
content = VGroup(numbers, bit_strings, errors)
|
||||||
|
|
||||||
|
for group, word in zip(content, words):
|
||||||
|
group[1].shift(3 * DOWN)
|
||||||
|
group.move_to(DOWN)
|
||||||
|
group.match_x(word)
|
||||||
|
|
||||||
|
self.play(*map(Write, numbers))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
TransformFromCopy(numbers, bit_strings),
|
||||||
|
lag_ratio=0.01,
|
||||||
|
run_time=2,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeInFrom(errors, 3 * LEFT))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
class NewSceneName(Scene):
|
class NewSceneName(Scene):
|
||||||
|
|
Loading…
Add table
Reference in a new issue