Many more ode1 scenes and fixes as the video gets edited

This commit is contained in:
Grant Sanderson 2019-03-28 16:20:09 -07:00
parent ea4df1f41e
commit 34851761e2
9 changed files with 1267 additions and 135 deletions

View file

@ -6,8 +6,10 @@ from active_projects.ode.part1.wordy_scenes import *
OUTPUT_DIRECTORY = "ode/part1"
ALL_SCENE_CLASSES = [
VectorFieldTest,
IntroducePendulum,
MultiplePendulumsOverlayed,
PeriodFormula,
FormulasAreLies,
MediumAnglePendulum,
MediumHighAnglePendulum,
@ -18,21 +20,31 @@ ALL_SCENE_CLASSES = [
VeryLowAnglePendulum,
FormulasAreLies,
TourOfDifferentialEquations,
WherePendulumLeads,
LongDoublePendulum,
# FollowThisThread,
StrogatzQuote,
ShowHorizontalDashedLine,
RabbitFoxPopulations,
RabbitFoxEquation,
# Something...
ShowGravityAcceleration,
AnalyzePendulumForce,
ShowSineValues,
BuildUpEquation,
ShowDerivativeVideo,
SubtleAirCurrents,
SimpleDampenedPendulum,
DefineODE,
SecondOrderEquationExample,
ODEvsPDEinFrames,
ProveTeacherWrong,
SetAsideSeekingSolution,
ReferencePiCollisionStateSpaces,
# VisualizeHeightSlopeCurvature,
VisualizeStates,
ReferencePiCollisionStateSpaces,
IntroduceVectorField,
XComponentArrows,
BreakingSecondOrderIntoTwoFirstOrder,
ShowPendulumPhaseFlow,
ShowHighVelocityCase,
@ -42,10 +54,18 @@ ALL_SCENE_CLASSES = [
LorenzVectorField,
ThreeBodiesInSpace,
AltThreeBodiesInSpace,
ThreeBodyTitle,
ThreeBodySymbols,
AskAboutActuallySolving,
WriteODESolvingCode,
TakeManyTinySteps,
InaccurateComputation,
HungerForExactness,
ShowRect,
JumpToThisPoint,
ThreeBodyEquation,
ItGetsWorse,
ChaosTitle,
RevisitQuote,
EndScreen,
]

View file

@ -287,6 +287,9 @@ class ThetaVsTAxes(Axes):
y_axis.label = theta_label
y_axis.add(theta_label)
self.y_axis_label = theta_label
self.x_axis_label = t_label
x_axis.add_numbers()
y_axis.add(self.get_y_axis_coordinates(y_axis))
@ -357,6 +360,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
"length": 3,
"top_point": 4 * RIGHT,
"weight_diameter": 0.35,
"gravity": 20,
},
"theta_vs_t_axes_config": {
"y_max": PI / 4,
@ -366,6 +370,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
"unit_size": 2,
"tip_length": 0.3,
},
"x_max": 12,
"number_line_config": {
"stroke_width": 2,
}
@ -378,12 +383,13 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
def construct(self):
self.add_pendulum()
self.label_pi_creatures()
# self.label_pi_creatures()
self.label_pendulum()
self.add_graph()
self.label_function()
self.show_graph_period()
self.show_length_and_gravity()
self.tweak_length_and_gravity()
# self.tweak_length_and_gravity()
def create_pi_creatures(self):
randy = Randolph(color=BLUE_C)
@ -437,7 +443,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
GrowArrow(morty_label.arrow),
morty.change, "raise_right_hand",
)
self.wait()
self.wait(2)
def label_pendulum(self):
pendulum = self.pendulum
@ -446,18 +452,18 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
rect = SurroundingRectangle(label, buff=0.5 * SMALL_BUFF)
rect.add_updater(lambda r: r.move_to(label))
self.add(rect)
for pi in randy, morty:
pi.add_updater(
lambda m: m.look_at(pendulum.weight)
)
self.play(randy.change, "pondering")
self.play(morty.change, "pondering")
self.wait(3)
randy.clear_updaters()
morty.clear_updaters()
self.play(
ShowCreationThenFadeOut(rect),
ShowCreationThenDestruction(
label.copy().set_style(
fill_opacity=0,
stroke_color=PINK,
stroke_width=2,
)
),
randy.change, "pondering",
morty.change, "pondering",
)
self.wait()
@ -467,7 +473,10 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
axes.to_corner(UL)
self.play(
Restore(self.camera_frame),
Restore(
self.camera_frame,
rate_func=squish_rate_func(smooth, 0, 0.9),
),
DrawBorderThenFill(
axes,
rate_func=squish_rate_func(smooth, 0.5, 1),
@ -481,11 +490,30 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
),
run_time=3,
)
self.wait(2)
self.graph = axes.get_live_drawn_graph(self.pendulum)
self.wait(1.5)
self.graph = axes.get_live_drawn_graph(self.pendulum)
self.add(self.graph)
self.wait(4)
def label_function(self):
hm_word = TextMobject("Simple harmonic motion")
hm_word.scale(1.25)
hm_word.to_edge(UP)
formula = TexMobject(
"=\\theta_0 \\cos(\\sqrt{g / L} t)"
)
formula.next_to(
self.axes.y_axis_label, RIGHT, SMALL_BUFF
)
formula.set_stroke(width=0, background=True)
self.play(FadeInFrom(hm_word, DOWN))
self.wait()
self.play(
Write(formula),
hm_word.to_corner, UR
)
def show_graph_period(self):
pendulum = self.pendulum
@ -503,13 +531,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
line.shift(SMALL_BUFF * RIGHT)
brace = Brace(line, UP, buff=SMALL_BUFF)
brace.add_to_back(brace.copy().set_style(BLACK, 10))
formula = TexMobject(
"\\sqrt{\\,", "2\\pi", "L", "/", "g", "}",
tex_to_color_map={
"L": BLUE,
"g": YELLOW,
}
)
formula = get_period_formula()
formula.next_to(brace, UP, SMALL_BUFF)
self.period_formula = formula
@ -537,29 +559,22 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
self.pendulum,
length_multiple=0.5 / 9.8,
)
down_vectors = self.get_down_vectors()
down_vectors.set_color(YELLOW)
down_vectors.set_opacity(0.5)
self.play(ShowCreationThenDestructionAround(L))
dot = Dot(fill_opacity=0.25)
dot.move_to(L)
self.play(
ShowCreationThenDestructionAround(L),
ShowCreation(new_rod),
dot.move_to, new_rod,
dot.fade, 1,
)
self.remove(dot)
self.play(FadeOut(new_rod))
self.wait()
self.play(ShowCreationThenDestructionAround(g))
dot.move_to(g)
dot.set_fill(opacity=0.5)
self.play(
ShowCreationThenDestructionAround(g),
GrowArrow(g_vect),
dot.move_to, g_vect,
dot.fade, 1,
)
self.remove(dot)
self.wait(2)
self.play(self.get_down_vectors_animation(down_vectors))
self.wait(6)
self.gravity_vector = g_vect
@ -593,15 +608,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
# new_pendulum_config["initial_theta"] = pendulum.get_theta()
new_pendulum = Pendulum(**new_pendulum_config)
down_vectors = VGroup(*[
Vector(0.5 * DOWN)
for x in range(10 * 150)
])
down_vectors.arrange_in_grid(10, 150, buff=MED_SMALL_BUFF)
down_vectors.set_color_by_gradient(BLUE, RED)
# for vect in down_vectors:
# vect.shift(0.1 * np.random.random(3))
down_vectors.to_edge(RIGHT)
down_vectors = self.get_down_vectors()
self.play(randy.change, "happy")
self.play(
@ -624,10 +631,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
g_vect.scale(2)
self.play(
FadeOut(graph2),
LaggedStart(*[
GrowArrow(v, rate_func=there_and_back)
for v in down_vectors
], lag_ratio=0.0005, run_time=2, remover=True)
self.get_down_vectors_animation(down_vectors)
)
self.play(
FadeIn(graph3),
@ -635,6 +639,30 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
)
self.wait(6)
#
def get_down_vectors(self):
down_vectors = VGroup(*[
Vector(0.5 * DOWN)
for x in range(10 * 150)
])
down_vectors.arrange_in_grid(10, 150, buff=MED_SMALL_BUFF)
down_vectors.set_color_by_gradient(BLUE, RED)
# for vect in down_vectors:
# vect.shift(0.1 * np.random.random(3))
down_vectors.to_edge(RIGHT)
return down_vectors
def get_down_vectors_animation(self, down_vectors):
return LaggedStart(
*[
GrowArrow(v, rate_func=there_and_back)
for v in down_vectors
],
lag_ratio=0.0005,
run_time=2,
remover=True
)
class MultiplePendulumsOverlayed(Scene):
CONFIG = {
@ -868,6 +896,95 @@ class VeryLowAnglePendulum(LowAnglePendulum):
}
class WherePendulumLeads(PiCreatureScene):
def construct(self):
pendulum = Pendulum(
top_point=UP,
length=3,
gravity=20,
)
pendulum.start_swinging()
l_title = TextMobject("Linearization")
l_title.scale(1.5)
l_title.to_corner(UL)
c_title = TextMobject("Chaos")
c_title.scale(1.5)
c_title.move_to(l_title)
c_title.move_to(
c_title.get_center() * np.array([-1, 1, 1])
)
get_theta = pendulum.get_theta
spring = always_redraw(
lambda: ParametricFunction(
lambda t: np.array([
np.cos(TAU * t) + (1.4 + get_theta()) * t,
np.sin(TAU * t) - 0.5,
0,
]),
t_min=-0.5,
t_max=7,
color=GREY,
sheen_factor=1,
sheen_direction=UL,
).scale(0.2).to_edge(LEFT, buff=0)
)
spring_rect = SurroundingRectangle(
spring, buff=MED_LARGE_BUFF,
stroke_width=0,
fill_color=BLACK,
fill_opacity=0,
)
weight = Dot(radius=0.25)
weight.add_updater(lambda m: m.move_to(
spring.points[-1]
))
weight.set_color(BLUE)
weight.set_sheen(1, UL)
spring_system = VGroup(spring, weight)
linear_formula = TexMobject(
"\\frac{d \\vec{\\textbf{x}}}{dt}="
"A\\vec{\\textbf{x}}"
)
linear_formula.next_to(spring, UP, LARGE_BUFF)
linear_formula.match_x(l_title)
randy = self.pi_creature
randy.set_height(2)
randy.center()
randy.to_edge(DOWN)
randy.shift(3 * LEFT)
q_marks = TexMobject("???")
q_marks.next_to(randy, UP)
self.add(pendulum, randy)
self.play(
randy.change, "pondering", pendulum,
FadeInFromDown(q_marks, lag_ratio=0.3)
)
self.play(randy.look_at, pendulum)
self.wait(5)
self.play(
Animation(VectorizedPoint(pendulum.get_top())),
FadeOutAndShift(q_marks, UP, lag_ratio=0.3),
)
self.add(spring_system)
self.play(
FadeOut(spring_rect),
FadeInFrom(linear_formula, UP),
FadeInFromDown(l_title),
)
self.play(FadeInFromDown(c_title))
self.wait(8)
class LongDoublePendulum(ExternallyAnimatedScene):
pass
class AnalyzePendulumForce(MovingCameraScene):
CONFIG = {
"pendulum_config": {
@ -1215,13 +1332,22 @@ class AnalyzePendulumForce(MovingCameraScene):
self.play(FocusOn(pendulum.theta_label))
self.play(Indicate(pendulum.theta_label))
old_updaters = pendulum.get_updaters()
pendulum.clear_updaters(recursive=False)
pendulum.start_swinging()
pendulum_copy = pendulum.deepcopy()
pendulum_copy.clear_updaters()
pendulum_copy.fade(1)
pendulum_copy.start_swinging()
def new_updater(p):
p.set_theta(pendulum_copy.get_theta())
pendulum.add_updater(new_updater)
self.add(pendulum_copy)
self.wait(5)
pendulum.clear_updaters()
for updater in old_updaters:
pendulum.add_updater(updater)
pendulum_copy.end_swinging()
self.remove(pendulum_copy)
pendulum.remove_updater(new_updater)
self.update_mobjects(0)
def show_arc_length(self):
pendulum = self.pendulum
@ -1664,6 +1790,18 @@ class BuildUpEquation(Scene):
self.wait()
class SimpleDampenedPendulum(Scene):
def construct(self):
pendulum = Pendulum(
top_point=ORIGIN,
initial_theta=150 * DEGREES,
mu=0.5,
)
self.add(pendulum)
pendulum.start_swinging()
self.wait(20)
class NewSceneName(Scene):
def construct(self):
pass

View file

@ -951,13 +951,13 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
self.initialize_vector_field()
self.add(self.vector_field)
self.add_flexible_state()
self.show_high_vector()
self.show_trajectory()
def show_trajectory(self):
def add_flexible_state(self):
super().add_flexible_state()
state = self.state
plane = self.plane
field = self.vector_field
frame = self.camera_frame
state.to_edge(DOWN, buff=SMALL_BUFF),
start_point = plane.coords_to_point(0, 4)
@ -965,6 +965,33 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
dot.move_to(start_point)
state.update()
self.dot = dot
self.start_point = start_point
def show_high_vector(self):
field = self.vector_field
top_vectors = VGroup(*filter(
lambda a: np.all(a.get_center() > [-10, 1.5, -10]),
field
)).copy()
top_vectors.set_stroke(PINK, 3)
top_vectors.sort(lambda p: p[0])
self.play(
ShowCreationThenFadeOut(
top_vectors,
run_time=2,
lag_ratio=0.01,
)
)
def show_trajectory(self):
state = self.state
field = self.vector_field
frame = self.camera_frame
dot = self.dot
start_point = self.start_point
traj = VMobject()
traj.start_new_path(start_point)
dt = 0.01
@ -998,6 +1025,10 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
class TweakMuInFormula(Scene):
def construct(self):
self.add(FullScreenFadeRectangle(
opacity=0.75,
))
ode = get_ode()
ode.to_edge(DOWN, buff=LARGE_BUFF)
mu = ode.get_part_by_tex("\\mu")

View file

@ -111,7 +111,11 @@ class FormulasAreLies(PiCreatureScene):
class ProveTeacherWrong(TeacherStudentsScene):
def construct(self):
tex_config = {
"tex_to_color_map": {"{\\theta}": BLUE}
"tex_to_color_map": {
"{\\theta}": BLUE,
"{\\dot\\theta}": YELLOW,
"{\\ddot\\theta}": RED,
}
}
func = TexMobject(
"{\\theta}(t)", "=",
@ -119,23 +123,24 @@ class ProveTeacherWrong(TeacherStudentsScene):
**tex_config,
)
d_func = TexMobject(
"\\dot {\\theta}(t)", "=",
"{\\dot\\theta}(t)", "=",
"-\\left(\\sqrt{g / L}\\right)",
"\\theta_0", "\\sin(\\sqrt{g / L} \\cdot t)",
**tex_config,
)
dd_func = TexMobject(
"\\ddot {\\theta}(t)", "=",
"{\\ddot\\theta}(t)", "=",
"-\\left(g / L\\right)",
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)",
**tex_config,
)
ode = TexMobject(
"\\ddot {\\theta}({t})", "=",
"-\\mu \\dot {\\theta}({t})",
"-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
**tex_config,
)
# ode = TexMobject(
# "\\ddot {\\theta}({t})", "=",
# "-\\mu \\dot {\\theta}({t})",
# "-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
# **tex_config,
# )
ode = get_ode()
arrows = [TexMobject("\\Downarrow") for x in range(2)]
VGroup(func, d_func, dd_func, ode, *arrows).scale(0.7)
@ -376,9 +381,44 @@ class HungerForExactness(TeacherStudentsScene):
)
self.wait()
self.wait(3)
self.change_student_modes("tired", "sad", "concerned_musician")
self.wait(4)
self.look_at(solution)
self.wait(5)
self.play(
FadeOutAndShift(solution, 2 * LEFT),
Restore(ode),
self.get_student_changes(*3 * ["sick"])
self.get_student_changes(
"sick", "angry", "tired",
)
)
self.wait(3)
mystery = TexMobject(
"\\theta(t) = ???",
tex_to_color_map={"\\theta": BLUE},
)
mystery.scale(2)
mystery.to_edge(UP)
mystery.set_stroke(width=0, background=True)
self.play(
FadeInFromDown(mystery),
self.teacher.change, "pondering"
)
self.add(
AnimatedBoundary(mystery, stroke_width=1),
mystery,
)
self.change_all_student_modes("sad")
self.look_at(mystery)
self.wait(5)
class ItGetsWorse(TeacherStudentsScene):
def construct(self):
self.teacher_says("It gets\\\\worse")
self.change_student_modes(
"hesitant", "pleading", "erm"
)
self.wait(2)

View file

@ -35,6 +35,16 @@ def get_ode():
return ode
def get_period_formula():
return TexMobject(
"\\sqrt{\\,", "2\\pi", "L", "/", "g", "}",
tex_to_color_map={
"L": BLUE,
"g": YELLOW,
}
)
def pendulum_vector_field_func(point, mu=0.1, g=9.8, L=3):
theta, omega = point[:2]
return np.array([

View file

@ -3,6 +3,8 @@ from active_projects.ode.part1.shared_constructs import *
from active_projects.ode.part1.pendulum import Pendulum
from active_projects.ode.part1.pendulum import ThetaVsTAxes
from active_projects.ode.part1.phase_space import IntroduceVectorField
from old_projects.div_curl import PhaseSpaceOfPopulationModel
from old_projects.div_curl import ShowTwoPopulations
# Scenes
@ -15,16 +17,21 @@ class VectorFieldTest(Scene):
)
mu_tracker = ValueTracker(1)
field = VectorField(
lambda p: pendulum_vector_field(
lambda p: pendulum_vector_field_func(
plane.point_to_coords(p),
mu=mu_tracker.get_value()
),
delta_x=0.5,
delta_y=0.5,
max_magnitude=4,
max_magnitude=6,
opacity=0.5,
# length_func=lambda norm: norm,
)
field.set_opacity(1)
self.add(plane, field)
return
stream_lines = StreamLines(
field.func,
delta_x=0.5,
@ -39,6 +46,26 @@ class VectorFieldTest(Scene):
self.wait(10)
class ShowRect(Scene):
def construct(self):
rect = Rectangle()
rect.set_stroke(YELLOW)
rect.set_height(1)
rect.set_width(3, stretch=True)
self.play(ShowCreation(rect))
self.play(FadeOut(rect))
class PeriodFormula(Scene):
def construct(self):
formula = get_period_formula()
formula.scale(2)
q_mark = TexMobject("?")
q_mark.scale(3)
q_mark.next_to(formula, RIGHT)
self.add(formula, q_mark)
class TourOfDifferentialEquations(MovingCameraScene):
CONFIG = {
"screen_rect_style": {
@ -214,13 +241,32 @@ class HeatEquationPreview(ExternallyAnimatedScene):
pass
class ShowHorizontalDashedLine(Scene):
def construct(self):
line = DashedLine(LEFT_SIDE, RIGHT_SIDE)
self.play(ShowCreation(line))
self.wait()
class RabbitFoxPopulations(ShowTwoPopulations):
pass
class RabbitFoxEquation(PhaseSpaceOfPopulationModel):
def construct(self):
equations = self.get_equations()
self.add(equations)
class ShowGravityAcceleration(Scene):
def construct(self):
self.add_gravity_field()
self.add_title()
self.pulse_gravity_down()
self.show_g_value()
self.show_trajectory()
self.combine_v_vects()
self.show_g_symbol()
def add_gravity_field(self):
gravity_field = self.gravity_field = VectorField(
@ -238,17 +284,11 @@ class ShowGravityAcceleration(Scene):
title = self.title = TextMobject("Gravitational acceleration")
title.scale(1.5)
title.to_edge(UP)
g_eq = self.g_eq = TexMobject(
"{g}", "=", "-9.8", "\\frac{\\text{m/s}}{\\text{s}}",
**Lg_formula_config
title.add_background_rectangle(
buff=0.05,
opacity=1,
)
g_eq.next_to(title, DOWN)
for mob in title, g_eq:
mob.add_background_rectangle_to_submobjects(
buff=0.05,
opacity=1,
)
self.add(title, g_eq)
self.play(FadeInFromDown(title))
def pulse_gravity_down(self):
field = self.gravity_field
@ -260,7 +300,36 @@ class ShowGravityAcceleration(Scene):
)
for vector in field
]), run_time=2, lag_ratio=0.001)
self.add(self.title, self.g_eq)
self.add(self.title)
def show_g_value(self):
title = self.title
g_eq = self.g_eq = TexMobject(
"-9.8", "{\\text{m/s}", "\\over", "\\text{s}}",
**Lg_formula_config
)
g_eq.add_background_rectangle_to_submobjects()
g_eq.scale(2)
g_eq.center()
num, ms, per, s = g_eq
self.add(num)
self.wait(0.75)
self.play(
FadeInFrom(ms, 0.25 * DOWN, run_time=0.5)
)
self.wait(0.25)
self.play(LaggedStart(
GrowFromPoint(per, per.get_left()),
FadeInFrom(s, 0.5 * UP),
lag_ratio=0.7,
run_time=0.75
))
self.wait()
self.play(
g_eq.scale, 0.5,
g_eq.next_to, title, DOWN,
)
def show_trajectory(self):
ball = Circle(
@ -329,6 +398,18 @@ class ShowGravityAcceleration(Scene):
rate_func=squish_rate_func(smooth, 0, 0.1)
)
time_label = TextMobject("Time = ")
time_label.shift(MED_SMALL_BUFF * LEFT)
time_tracker = ValueTracker(0)
time = DecimalNumber(0)
time.next_to(time_label, RIGHT)
time.add_updater(lambda d, dt: d.set_value(
time_tracker.get_value()
))
time_group = VGroup(time_label, time)
time_group.center().to_edge(DOWN)
self.add(time_group)
ball_copies = VGroup()
v_vect_copies = VGroup()
self.add(dashed_graph, ball)
@ -353,11 +434,16 @@ class ShowGravityAcceleration(Scene):
ShowCreation(dashed_graph, **kw),
MoveAlongPath(ball, graph, **kw),
MoveAlongPath(v_point, velocity_graph, **kw),
ApplyMethod(
time_tracker.increment_value, 1,
rate_func=linear
),
flash,
run_time=1,
)
dashed_graph.restore()
randy.clear_updaters()
self.play(FadeOut(time_group))
self.wait()
self.v_vects = v_vect_copies
@ -406,16 +492,30 @@ class ShowGravityAcceleration(Scene):
)
self.wait()
def show_g_symbol(self):
g = TexMobject("g")
brace = Brace(self.g_eq[0][2:], UP, buff=SMALL_BUFF)
g.scale(1.5)
g.next_to(brace, UP)
g.set_color(YELLOW)
self.play(
FadeOut(self.title),
GrowFromCenter(brace),
FadeInFrom(g, UP),
)
self.wait()
class ShowDerivativeVideo(Scene):
CONFIG = {
"camera_config": {"background_color": DARKER_GREY}
}
def construct(self):
title = TextMobject("Essence of Calculus")
title.scale(1.25)
title = TextMobject("Essence of", "Calculus")
title.scale(1.5)
title.to_edge(UP)
title2 = TextMobject("Essence of", "Linear Algebra")
title2.scale(1.5)
title2.move_to(title, DOWN)
rect = ScreenRectangle(height=6)
rect = rect.copy()
rect.set_style(
@ -428,6 +528,8 @@ class ShowDerivativeVideo(Scene):
self.add(title, rect)
self.add(animated_rect)
self.wait(5)
self.play(ReplacementTransform(title, title2))
self.wait(10)
@ -483,7 +585,7 @@ class DefineODE(Scene):
def write_differential_equation(self):
de_word = TextMobject("Differential", "Equation")
de_word.to_edge(UP)
de_word.to_edge(UP, buff=MED_SMALL_BUFF)
equation = get_ode()
equation.next_to(de_word, DOWN)
@ -777,11 +879,7 @@ class DefineODE(Scene):
self.second_order_word = so
def show_higher_order_examples(self):
main_example = VGroup(
self.second_order_word,
self.ode_initials,
self.equation
)
main_example = self.get_main_example()
tex_config = {"tex_to_color_map": {"{x}": BLUE}}
example3 = VGroup(
TextMobject("Third order ODE"),
@ -821,6 +919,13 @@ class DefineODE(Scene):
)
self.wait(2)
def get_main_example(self):
return VGroup(
self.second_order_word,
self.ode_initials,
self.equation
)
def show_changing_curvature_group(self):
t_tracker = self.t_tracker
curvature_group = self.curvature_group
@ -828,7 +933,8 @@ class DefineODE(Scene):
graph = VMobject()
graph.pointwise_become_partial(
self.fake_graph,
0.25, 1,
t_tracker.get_value() / self.axes.x_max,
1,
)
dashed_graph = DashedVMobject(graph, num_dashes=100)
dashed_graph.set_stroke(GREEN, 1)
@ -844,14 +950,397 @@ class DefineODE(Scene):
self.wait()
class ODEvsPDEinFrames(Scene):
# Largely a copy of DefineODE, which is not great.
# But what can you do?
class SecondOrderEquationExample(DefineODE):
def construct(self):
pass
self.add_graph()
self.write_differential_equation()
self.show_value_slope_curvature()
self.show_higher_order_examples()
self.show_changing_curvature_group()
def add_graph(self):
axes = self.axes = Axes(
x_min=0,
x_max=10.5,
y_min=-2.5,
y_max=2.5,
)
axes.center()
axes.to_edge(DOWN)
x_t = TexMobject("x", "(t)")
x_t.set_color_by_tex("x", BLUE)
t = TexMobject("t")
t.next_to(axes.x_axis.get_right(), UP)
x_t.next_to(axes.y_axis.get_top(), UP)
axes.add(t, x_t)
axes.add_coordinates()
self.add(axes)
def write_differential_equation(self):
de_word = TextMobject("Differential", "Equation")
de_word.scale(1.25)
de_word.to_edge(UP, buff=MED_SMALL_BUFF)
so_word = TextMobject("Second Order")
so_word.scale(1.25)
de_word.generate_target()
group = VGroup(so_word, de_word.target)
group.arrange(RIGHT)
group.to_edge(UP, buff=MED_SMALL_BUFF)
so_word.align_to(de_word.target[0], DOWN)
so_line = Line(LEFT, RIGHT, color=YELLOW)
so_line.match_width(so_word)
so_line.next_to(so_word, DOWN, buff=SMALL_BUFF)
equation = TexMobject(
"{\\ddot x}(t)", "=",
"-\\mu", "{\\dot x}(t)",
"-", "\\omega", "{x}(t)",
tex_to_color_map={
"{x}": BLUE,
"{\\dot x}": YELLOW,
"{\\ddot x}": RED,
}
)
equation.next_to(de_word, DOWN)
dd_x_part = equation[:2]
dd_x_rect = SurroundingRectangle(dd_x_part)
self.add(de_word, equation)
self.play(
MoveToTarget(de_word),
FadeInFrom(so_word, RIGHT),
GrowFromCenter(so_line),
)
self.play(ReplacementTransform(so_line, dd_x_rect))
self.play(FadeOut(dd_x_rect))
self.equation = equation
self.title = VGroup(*so_word, *de_word)
def show_value_slope_curvature(self):
axes = self.axes
graph = axes.get_graph(
lambda t: -2.5 * np.cos(2 * t) * np.exp(-0.2 * t)
)
tex_config = {
"tex_to_color_map": {
"{x}": BLUE,
"{\\dot x}": YELLOW,
"{\\ddot x}": RED,
},
"height": 0.5,
}
x, d_x, dd_x = [
TexMobject(
"{" + s + "x}(t)",
**tex_config
)
for s in ("", "\\dot ", "\\ddot ")
]
t_tracker = ValueTracker(1.25)
get_t = t_tracker.get_value
def get_point(t):
return graph.point_from_proportion(t / axes.x_max)
def get_dot():
return Dot(get_point(get_t())).scale(0.5)
def get_v_line():
point = get_point(get_t())
x_point = axes.x_axis.number_to_point(
axes.x_axis.point_to_number(point)
)
return DashedLine(
x_point, point,
dash_length=0.025,
stroke_color=BLUE,
stroke_width=2,
)
def get_tangent_line(curve, alpha):
line = Line(
ORIGIN, 1.5 * RIGHT,
color=YELLOW,
stroke_width=1.5,
)
da = 0.0001
p0 = curve.point_from_proportion(alpha)
p1 = curve.point_from_proportion(alpha - da)
p2 = curve.point_from_proportion(alpha + da)
angle = angle_of_vector(p2 - p1)
line.rotate(angle)
line.move_to(p0)
return line
def get_slope_line():
return get_tangent_line(
graph, get_t() / axes.x_max
)
def get_curve():
curve = VMobject()
t = get_t()
curve.set_points_smoothly([
get_point(t + a)
for a in np.linspace(-0.5, 0.5, 11)
])
curve.set_stroke(RED, 1)
return curve
v_line = always_redraw(get_v_line)
dot = always_redraw(get_dot)
slope_line = always_redraw(get_slope_line)
curve = always_redraw(get_curve)
x.next_to(v_line, RIGHT, SMALL_BUFF)
d_x.next_to(slope_line.get_end(), UP, SMALL_BUFF)
dd_x.next_to(curve.get_end(), RIGHT, SMALL_BUFF)
xs = VGroup(x, d_x, dd_x)
words = VGroup(
TextMobject("= Height").set_color(BLUE),
TextMobject("= Slope").set_color(YELLOW),
TextMobject("= ``Curvature''").set_color(RED),
)
words.scale(0.75)
for word, sym in zip(words, xs):
word.next_to(sym, RIGHT, buff=2 * SMALL_BUFF)
sym.word = word
self.play(
ShowCreation(v_line),
FadeInFromPoint(dot, v_line.get_start()),
FadeInFrom(x, DOWN),
FadeInFrom(x.word, DOWN),
)
self.add(slope_line, dot)
self.play(
ShowCreation(slope_line),
FadeInFrom(d_x, LEFT),
FadeInFrom(d_x.word, LEFT),
)
a_tracker = ValueTracker(0)
curve_copy = curve.copy()
changing_slope = always_redraw(
lambda: get_tangent_line(
curve_copy,
a_tracker.get_value(),
).set_stroke(
opacity=there_and_back(a_tracker.get_value())
)
)
self.add(curve, dot)
self.play(
ShowCreation(curve),
FadeInFrom(dd_x, LEFT),
FadeInFrom(dd_x.word, LEFT),
)
self.add(changing_slope)
self.play(
a_tracker.set_value, 1,
run_time=3,
)
self.remove(changing_slope, a_tracker)
self.t_tracker = t_tracker
self.curvature_group = VGroup(
v_line, slope_line, curve, dot
)
self.curvature_group_labels = VGroup(xs, words)
self.fake_graph = graph
def get_main_example(self):
return VGroup(
self.equation,
self.title,
)
# class VisualizeHeightSlopeCurvature(DefineODE):
# CONFIG = {
# "pendulum_config": {
# "length": 2,
# "top_point": 5 * RIGHT + 2 * UP,
# "initial_theta": 175 * DEGREES,
# "mu": 0.3,
# },
# }
# def construct(self):
# self.add_graph()
# self.show_value_slope_curvature()
# self.show_changing_curvature_group()
class ODEvsPDEinFrames(Scene):
CONFIG = {
"camera_config": {"background_color": DARKER_GREY}
}
def construct(self):
frames = VGroup(*[
ScreenRectangle(
height=3.5,
fill_opacity=1,
fill_color=BLACK,
stroke_width=0,
)
for x in range(2)
])
frames.arrange(RIGHT, buff=LARGE_BUFF)
frames.shift(0.5 * DOWN)
animated_frames = VGroup(*[
AnimatedBoundary(
frame,
cycle_rate=0.2,
max_stroke_width=1,
)
for frame in frames
])
titles = VGroup(
# TextMobject("ODEs"),
# TextMobject("PDEs"),
TextMobject("Ordinary", "Differential", "Equations"),
TextMobject("Partial", "Differential", "Equations"),
)
for title, frame in zip(titles, frames):
title.arrange(
DOWN,
buff=MED_SMALL_BUFF,
aligned_edge=LEFT
)
title.next_to(frame, UP, MED_LARGE_BUFF)
title.initials = VGroup(*[
part[0] for part in title
])
titles[0][1].shift(0.05 * UP)
# ODE content
ode = get_ode()
ode.set_width(frames[0].get_width() - MED_LARGE_BUFF)
ode.next_to(frames[0].get_top(), DOWN)
ts = ode.get_parts_by_tex("{t}")
one_input = TextMobject("One input")
one_input.next_to(frames[0].get_bottom(), UP)
o_arrows = VGroup(*[
Arrow(
one_input.get_top(),
t.get_bottom(),
buff=0.2,
color=WHITE,
max_tip_length_to_length_ratio=0.075,
path_arc=pa
)
for t, pa in zip(ts, [-0.7, 0, 0.7])
])
o_arrows.set_stroke(width=3)
frames[0].add(ode, one_input, o_arrows)
# PDE content
pde = TexMobject(
"""
\\frac{\\partial T}{\\partial t}
{(x, y, t)} =
\\frac{\\partial^2 T}{\\partial x^2}
{(x, y, t)} +
\\frac{\\partial^2 T}{\\partial y^2}
{(x, y, t)}
""",
tex_to_color_map={"{(x, y, t)}": WHITE}
)
pde.set_width(frames[1].get_width() - MED_LARGE_BUFF)
pde.next_to(frames[1].get_top(), DOWN)
inputs = pde.get_parts_by_tex("{(x, y, t)}")
multi_input = TextMobject("Multiple inputs")
multi_input.next_to(frames[1].get_bottom(), UP)
p_arrows = VGroup(*[
Arrow(
multi_input.get_top(),
mob.get_bottom(),
buff=0.2,
color=WHITE,
max_tip_length_to_length_ratio=0.075,
path_arc=pa
)
for mob, pa in zip(inputs, [-0.7, 0, 0.7])
])
p_arrows.set_stroke(width=3)
frames[1].add(pde, multi_input, p_arrows)
self.add(
frames[0],
animated_frames[0],
titles[0]
)
self.play(
Write(one_input),
ShowCreation(o_arrows, lag_ratio=0.5)
)
self.wait(2)
self.play(titles[0].initials.set_color, BLUE)
self.wait(7)
# Transition
self.play(
TransformFromCopy(*titles),
TransformFromCopy(*frames),
)
self.play(VFadeIn(animated_frames[1]))
self.wait()
self.play(titles[1].initials.set_color, YELLOW)
self.wait(30)
class ReferencePiCollisionStateSpaces(Scene):
CONFIG = {
"camera_config": {"background_color": DARKER_GREY}
}
def construct(self):
pass
title = TextMobject("The block collision puzzle")
title.scale(1.5)
title.to_edge(UP)
self.add(title)
frames = VGroup(*[
ScreenRectangle(
height=3.5,
fill_opacity=1,
fill_color=BLACK,
stroke_width=0,
)
for x in range(2)
])
frames.arrange(RIGHT, buff=LARGE_BUFF)
boundary = AnimatedBoundary(frames)
self.add(frames, boundary)
self.wait(15)
class XComponentArrows(Scene):
def construct(self):
field = VectorField(
lambda p: np.array([p[1], 0, 0])
)
field.set_opacity(0.75)
for u in (1, -1):
field.sort(lambda p: u * p[0])
self.play(LaggedStartMap(
GrowArrow, field,
lag_ratio=0.1,
run_time=1
))
self.play(FadeOut(field))
class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
@ -879,6 +1368,14 @@ class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
system1.next_to(sys_word, DOWN)
system2.move_to(system1)
theta_dots = VGroup(*filter(
lambda m: (
isinstance(m, SingleStringTexMobject) and
"{\\dot\\theta}" == m.get_tex_string()
),
system1.get_family(),
))
self.add(ode)
self.play(FadeInFrom(so_word, 0.5 * DOWN))
self.wait()
@ -905,6 +1402,13 @@ class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
FadeInFromDown(sys_word)
)
self.wait()
self.play(LaggedStartMap(
ShowCreationThenFadeAround,
theta_dots,
surrounding_rectangle_config={
"color": PINK,
}
))
self.play(ReplacementTransform(system1, system2))
self.wait()
@ -993,6 +1497,13 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
axes.set_stroke(width=0.5)
self.add(axes)
# Orient
self.set_camera_orientation(
phi=70 * DEGREES,
theta=-110 * DEGREES,
)
self.begin_ambient_camera_rotation()
def add_bodies(self):
masses = self.masses
colors = self.colors
@ -1071,11 +1582,6 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
self.add(traj, body)
def let_play(self):
self.set_camera_orientation(
phi=70 * DEGREES,
theta=-110 * DEGREES,
)
self.begin_ambient_camera_rotation()
# Break it up to see partial files as
# it's rendered
for x in range(int(self.play_time)):
@ -1127,6 +1633,20 @@ class AltThreeBodiesInSpace(ThreeBodiesInSpace):
}
class TwoBodiesInSpace(ThreeBodiesInSpace):
CONFIG = {
"colors": [GREY, BLUE],
"masses": [1, 6],
"play_time": 5,
}
def construct(self):
self.add_axes()
self.add_bodies()
self.add_trajectories()
self.let_play()
class DefineODECopy(DefineODE):
pass

View file

@ -37,6 +37,40 @@ class SmallAngleApproximationTex(Scene):
class StrogatzQuote(Scene):
def construct(self):
quote = self.get_quote()
movers = VGroup(*quote[:-1].family_members_with_points())
for mover in movers:
mover.save_state()
disc = Circle(radius=0.05)
disc.set_stroke(width=0)
disc.set_fill(BLACK, 0)
disc.move_to(mover)
mover.become(disc)
self.play(
FadeInFrom(quote.author_part, LEFT),
LaggedStartMap(
# FadeInFromLarge,
# quote[:-1].family_members_with_points(),
Restore, movers,
lag_ratio=0.005,
run_time=2,
)
# FadeInFromDown(quote[:-1]),
# lag_ratio=0.01,
)
self.wait()
self.play(
Write(quote.law_part.copy().set_color(YELLOW)),
run_time=1,
)
self.wait()
self.play(
Write(quote.language_part.copy().set_color(BLUE)),
run_time=1.5,
)
self.wait(2)
def get_quote(self):
law_words = "laws of physics"
language_words = "language of differential equations"
author = "-Steven Strogatz"
@ -51,46 +85,58 @@ class StrogatzQuote(Scene):
arg_separator=" ",
substrings_to_isolate=[law_words, language_words, author]
)
law_part = quote.get_part_by_tex(law_words)
language_part = quote.get_part_by_tex(language_words)
author_part = quote.get_part_by_tex(author)
quote.law_part = quote.get_part_by_tex(law_words)
quote.language_part = quote.get_part_by_tex(language_words)
quote.author_part = quote.get_part_by_tex(author)
quote.set_width(12)
quote.to_edge(UP)
quote[-2].shift(SMALL_BUFF * LEFT)
author_part.shift(RIGHT + 0.5 * DOWN)
author_part.scale(1.2, about_edge=UL)
quote.author_part.shift(RIGHT + 0.5 * DOWN)
quote.author_part.scale(1.2, about_edge=UL)
return quote
class ShowSineValues(Scene):
def construct(self):
angle_tracker = ValueTracker(60 * DEGREES)
get_angle = angle_tracker.get_value
formula = always_redraw(
lambda: self.get_sine_formula(get_angle())
)
self.add(formula)
movers = VGroup(*quote[:-1].family_members_with_points())
for mover in movers:
mover.save_state()
disc = Circle(radius=0.05)
disc.set_stroke(width=0)
disc.set_fill(BLACK, 0)
disc.move_to(mover)
mover.become(disc)
self.play(
FadeInFrom(author_part, LEFT),
LaggedStartMap(
# FadeInFromLarge,
# quote[:-1].family_members_with_points(),
Restore, movers,
lag_ratio=0.005,
run_time=2,
)
# FadeInFromDown(quote[:-1]),
# lag_ratio=0.01,
angle_tracker.set_value, 0,
run_time=3,
)
self.wait()
self.play(
Write(law_part.copy().set_color(YELLOW)),
run_time=1,
angle_tracker.set_value, 90 * DEGREES,
run_time=3,
)
self.wait()
self.play(
Write(language_part.copy().set_color(BLUE)),
run_time=1.5,
def get_sine_formula(self, angle):
sin, lp, rp = TexMobject(
"\\sin", "(", ") = "
)
self.wait(2)
input_part = Integer(
angle / DEGREES,
unit="^\\circ",
)
input_part.set_color(YELLOW)
output_part = DecimalNumber(
np.sin(input_part.get_value() * DEGREES),
num_decimal_places=3,
)
result = VGroup(
sin, lp, input_part, rp, output_part
)
result.arrange(RIGHT, buff=SMALL_BUFF)
sin.scale(1.1, about_edge=DOWN)
lp.align_to(rp, UP)
return result
class SetAsideSeekingSolution(Scene):
@ -141,6 +187,14 @@ class SetAsideSeekingSolution(Scene):
)
class ThreeBodyTitle(Scene):
def construct(self):
title = TextMobject("Three body problem")
title.scale(1.5)
title.to_edge(UP)
self.add(title)
class ThreeBodySymbols(Scene):
def construct(self):
self.init_coord_groups()
@ -260,3 +314,259 @@ class ThreeBodySymbols(Scene):
rate_func=linear,
)
self.play(FadeOut(coord_copies))
class ThreeBodyEquation(Scene):
def construct(self):
x1 = "\\vec{\\textbf{x}}_1"
x2 = "\\vec{\\textbf{x}}_2"
x3 = "\\vec{\\textbf{x}}_3"
kw = {
"tex_to_color_map": {
x1: RED,
x2: GREEN,
x3: BLUE,
}
}
equations = VGroup(*[
TexMobject(
"{d^2", t1, "\\over dt^2}", "=",
"G", "\\left("
"{" + m2, "(", t2, "-", t1, ")"
"\\over"
"||", t2, "-", t1, "||^3}",
"+",
"{" + m3, "(", t3, "-", t1, ")"
"\\over"
"||", t3, "-", t1, "||^3}",
"\\right)",
**kw
)
for t1, t2, t3, m1, m2, m3 in [
(x1, x2, x3, "m_1", "m_2", "m_3"),
(x2, x3, x1, "m_2", "m_3", "m_1"),
(x3, x1, x2, "m_3", "m_1", "m_2"),
]
])
equations.arrange(DOWN, buff=LARGE_BUFF)
self.play(LaggedStartMap(
FadeInFrom, equations,
lambda m: (m, UP),
lag_ratio=0.2,
))
self.wait()
class JumpToThisPoint(Scene):
def construct(self):
dot = Dot(color=YELLOW)
dot.scale(0.5)
arrow = Vector(DR, color=WHITE)
arrow.next_to(dot, UL, SMALL_BUFF)
words = TextMobject(
"Jump directly to\\\\",
"this point?",
)
words.add_background_rectangle_to_submobjects()
words.next_to(arrow.get_start(), UP, SMALL_BUFF)
self.play(
FadeInFromLarge(dot, 20),
rate_func=rush_into,
)
self.play(
GrowArrow(arrow),
FadeInFromDown(words),
)
class ChaosTitle(Scene):
def construct(self):
title = TextMobject("Chaos theorey")
title.scale(1.5)
title.to_edge(UP)
line = Line(LEFT, RIGHT)
line.set_width(FRAME_WIDTH - 1)
line.next_to(title, DOWN)
self.play(
Write(title),
ShowCreation(line),
)
self.wait()
class RevisitQuote(StrogatzQuote, PiCreatureScene):
def construct(self):
quote = self.get_quote()
quote.law_part.set_color(YELLOW)
quote.language_part.set_color(BLUE)
quote.set_stroke(BLACK, 6, background=True)
quote.scale(0.8, about_edge=UL)
new_langauge_part = TextMobject(
"\\Large Language of differential equations"
)
new_langauge_part.to_edge(UP)
new_langauge_part.match_style(quote.language_part)
randy = self.pi_creature
self.play(
FadeInFrom(quote[:-1], DOWN),
FadeInFrom(quote[-1:], LEFT),
randy.change, "raise_right_hand",
)
self.play(Blink(randy))
self.play(randy.change, "angry")
self.play(
Blink(randy),
VFadeOut(randy, run_time=3)
)
mover = VGroup(quote.language_part)
self.add(quote, mover)
self.play(
ReplacementTransform(
mover, new_langauge_part,
),
*[
FadeOut(part)
for part in quote
if part is not quote.language_part
],
run_time=2,
)
self.wait()
class EndScreen(PatreonEndScreen):
CONFIG = {
"specific_patrons": [
"Juan Benet",
"Vassili Philippov",
"Burt Humburg",
"Carlos Vergara Del Rio",
"Matt Russell",
"Scott Gray",
"soekul",
"Tihan Seale",
"Ali Yahya",
"dave nicponski",
"Evan Phillips",
"Graham",
"Joseph Kelly",
"Kaustuv DeBiswas",
"LambdaLabs",
"Lukas Biewald",
"Mike Coleman",
"Peter Mcinerney",
"Quantopian",
"Roy Larson",
"Scott Walter, Ph.D.",
"Yana Chernobilsky",
"Yu Jun",
"Jordan Scales",
"Lukas -krtek.net- Novy",
"John Shaughnessy",
"Britt Selvitelle",
"David Gow",
"J",
"Jonathan Wilson",
"Joseph John Cox",
"Magnus Dahlström",
"Randy C. Will",
"Ryan Atallah",
"Luc Ritchie",
"1stViewMaths",
"Adrian Robinson",
"Alexis Olson",
"Andreas Benjamin Brössel",
"Andrew Busey",
"Ankalagon",
"Antonio Juarez",
"Arjun Chakroborty",
"Art Ianuzzi",
"Awoo",
"Bernd Sing",
"Boris Veselinovich",
"Brian Staroselsky",
"Chad Hurst",
"Charles Southerland",
"Chris Connett",
"Christian Kaiser",
"Clark Gaebel",
"Cooper Jones",
"Danger Dai",
"Dave B",
"Dave Kester",
"David Clark",
"DeathByShrimp",
"Delton Ding",
"eaglle",
"emptymachine",
"Eric Younge",
"Eryq Ouithaqueue",
"Federico Lebron",
"Giovanni Filippi",
"Hal Hildebrand",
"Herman Dieset",
"Hitoshi Yamauchi",
"Isaac Jeffrey Lee",
"j eduardo perez",
"Jacob Magnuson",
"Jameel Syed",
"Jason Hise",
"Jeff Linse",
"Jeff Straathof",
"John Griffith",
"John Haley",
"John V Wertheim",
"Jonathan Eppele",
"Kai-Siang Ang",
"Kanan Gill",
"L0j1k",
"Lee Redden",
"Linh Tran",
"Ludwig Schubert",
"Magister Mugit",
"Mark B Bahu",
"Mark Heising",
"Martin Price",
"Mathias Jansson",
"Matt Langford",
"Matt Roveto",
"Matthew Cocke",
"Michael Faust",
"Michael Hardel",
"Mirik Gogri",
"Mustafa Mahdi",
"Márton Vaitkus",
"Nero Li",
"Nikita Lesnikov",
"Omar Zrien",
"Owen Campbell-Moore",
"Peter Ehrnstrom",
"RedAgent14",
"rehmi post",
"Richard Burgmann",
"Richard Comish",
"Ripta Pasay",
"Rish Kundalia",
"Robert Teed",
"Roobie",
"Ryan Williams",
"Samuel D. Judge",
"Solara570",
"Stevie Metke",
"Tal Einav",
"Ted Suzman",
"Valeriy Skobelev",
"Xavier Bernard",
"Yavor Ivanov",
"Yaw Etse",
"YinYangBalance.Asia",
"Zach Cardwell",
]
}

View file

@ -0,0 +1,63 @@
import numpy as np
# Physical constants
g = 9.8
L = 2
mu = 0.1
THETA_0 = np.pi / 3 # 60 degrees
THETA_DOT_0 = 0 # No initial angular velocity
# Definition of ODE
def get_theta_double_dot(theta, theta_dot):
return -mu * theta_dot - (g / L) * np.sin(theta)
# Solution to the differential equation
def theta(t):
# Initialize changing values
theta = THETA_0
theta_dot = THETA_DOT_0
delta_t = 0.01 # Some time step
for time in np.arange(0, t, delta_t):
# Take many little time steps of size delta_t
# until the total time is the function's input
theta_double_dot = get_theta_double_dot(
theta, theta_dot
)
theta += theta_dot * delta_t
theta_dot += theta_double_dot * delta_t
return theta

View file

@ -43,7 +43,7 @@ def stage_scenes(module_name):
# }
# TODO, fix this
animation_dir = os.path.join(
VIDEO_DIR, "clacks_solution2", "1440p60"
VIDEO_DIR, "ode", "part1", "1440p60"
)
#
files = os.listdir(animation_dir)