mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Scenes to show mismatch between approximated pendulum and real
This commit is contained in:
parent
ac9c04d3b8
commit
be2ce981d9
3 changed files with 229 additions and 0 deletions
|
@ -4,6 +4,12 @@ from active_projects.ode.part1.staging import *
|
|||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
ALL_SCENE_CLASSES = [
|
||||
IntroducePendulum,
|
||||
FormulasAreLies,
|
||||
HighAnglePendulum,
|
||||
MediumAnglePendulum,
|
||||
LowAnglePendulum,
|
||||
ApproxWordsLowAnglePendulum,
|
||||
FailedApproxWordsHighAnglePendulum,
|
||||
# Tests
|
||||
PendulumTest,
|
||||
VectorFieldTest,
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
|
||||
|
||||
Lg_formula_config = {
|
||||
"tex_to_color_map": {
|
||||
"\\theta_0": WHITE,
|
||||
"{L}": BLUE,
|
||||
"{g}": YELLOW,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Pendulum(VGroup):
|
||||
CONFIG = {
|
||||
"length": 3,
|
||||
|
@ -22,6 +31,9 @@ class Pendulum(VGroup):
|
|||
"fill_color": GREY_BROWN,
|
||||
"sheen_direction": UL,
|
||||
"sheen_factor": 0.5,
|
||||
"background_stroke_color": BLACK,
|
||||
"background_stroke_width": 3,
|
||||
"background_stroke_opacity": 0.5,
|
||||
},
|
||||
"dashed_line_config": {
|
||||
"num_dashes": 25,
|
||||
|
@ -514,6 +526,139 @@ class IntroducePendulum(MovingCameraScene):
|
|||
self.wait(6)
|
||||
|
||||
|
||||
class LowAnglePendulum(Scene):
|
||||
CONFIG = {
|
||||
"pendulum_config": {
|
||||
"initial_theta": 20 * DEGREES,
|
||||
"length": 2.0,
|
||||
"damping": 0,
|
||||
"top_point": ORIGIN,
|
||||
},
|
||||
"axes_config": {
|
||||
"y_axis_config": {"unit_size": 0.75},
|
||||
"x_axis_config": {
|
||||
"unit_size": 0.5,
|
||||
"numbers_to_show": range(2, 25, 2),
|
||||
"number_scale_val": 0.5,
|
||||
},
|
||||
"x_max": 25,
|
||||
"number_line_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
},
|
||||
"axes_corner": UL,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pendulum = Pendulum(**self.pendulum_config)
|
||||
axes = ThetaVsTAxes(**self.axes_config)
|
||||
axes.center()
|
||||
axes.to_corner(self.axes_corner, buff=LARGE_BUFF)
|
||||
graph = axes.get_live_drawn_graph(pendulum)
|
||||
|
||||
L = pendulum.length
|
||||
g = pendulum.gravity
|
||||
theta0 = pendulum.initial_theta
|
||||
prediction = axes.get_graph(
|
||||
lambda t: theta0 * np.cos(t * np.sqrt(g / L))
|
||||
)
|
||||
dashed_prediction = DashedVMobject(prediction, num_dashes=300)
|
||||
dashed_prediction.set_stroke(WHITE, 1)
|
||||
prediction_formula = TexMobject(
|
||||
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)"
|
||||
)
|
||||
prediction_formula.scale(0.75)
|
||||
prediction_formula.next_to(
|
||||
dashed_prediction, UP, SMALL_BUFF,
|
||||
)
|
||||
|
||||
theta0 = prediction_formula.get_part_by_tex("\\theta_0")
|
||||
theta0_brace = Brace(theta0, UP, buff=SMALL_BUFF)
|
||||
theta0_brace.stretch(0.5, 1, about_edge=DOWN)
|
||||
theta0_label = Integer(
|
||||
pendulum.initial_theta * 180 / PI,
|
||||
unit="^\\circ"
|
||||
)
|
||||
theta0_label.scale(0.75)
|
||||
theta0_label.next_to(theta0_brace, UP, SMALL_BUFF)
|
||||
|
||||
group = VGroup(theta0_brace, theta0_label, prediction_formula)
|
||||
group.shift_onto_screen(buff=MED_SMALL_BUFF)
|
||||
|
||||
self.add(axes, dashed_prediction, pendulum)
|
||||
self.play(
|
||||
ShowCreation(dashed_prediction, run_time=2),
|
||||
FadeInFromDown(prediction_formula),
|
||||
FadeInFromDown(theta0_brace),
|
||||
FadeInFromDown(theta0_label),
|
||||
)
|
||||
self.play(
|
||||
ShowCreationThenFadeAround(theta0_label),
|
||||
ShowCreationThenFadeAround(pendulum.theta_label),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
pendulum.start_swinging()
|
||||
self.add(graph)
|
||||
self.wait(30)
|
||||
|
||||
|
||||
class ApproxWordsLowAnglePendulum(Scene):
|
||||
def construct(self):
|
||||
period = TexMobject(
|
||||
"\\text{Period}", "\\approx",
|
||||
"2\\pi \\sqrt{\\,{L} / {g}}",
|
||||
**Lg_formula_config
|
||||
)
|
||||
checkmark = TexMobject("\\checkmark")
|
||||
checkmark.set_color(GREEN)
|
||||
checkmark.scale(2)
|
||||
checkmark.next_to(period, RIGHT, MED_LARGE_BUFF)
|
||||
|
||||
self.add(period, checkmark)
|
||||
|
||||
|
||||
class MediumAnglePendulum(LowAnglePendulum):
|
||||
CONFIG = {
|
||||
"pendulum_config": {
|
||||
"initial_theta": 50 * DEGREES,
|
||||
"n_steps_per_frame": 1000,
|
||||
},
|
||||
"axes_config": {
|
||||
"y_axis_config": {"unit_size": 0.75},
|
||||
"y_max": PI / 2,
|
||||
"y_min": -PI / 2,
|
||||
"number_line_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
},
|
||||
"pendulum_shift_vect": 1 * RIGHT,
|
||||
}
|
||||
|
||||
|
||||
class HighAnglePendulum(LowAnglePendulum):
|
||||
CONFIG = {
|
||||
"pendulum_config": {
|
||||
"initial_theta": 175 * DEGREES,
|
||||
"n_steps_per_frame": 1000,
|
||||
"top_point": 1.5 * DOWN,
|
||||
"length": 2,
|
||||
},
|
||||
"axes_config": {
|
||||
"y_axis_config": {"unit_size": 0.5},
|
||||
"y_max": PI,
|
||||
"y_min": -PI,
|
||||
"number_line_config": {
|
||||
"tip_length": 0.3,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
},
|
||||
"pendulum_shift_vect": 1 * RIGHT,
|
||||
}
|
||||
|
||||
|
||||
class PendulumTest(Scene):
|
||||
def construct(self):
|
||||
pendulum = Pendulum(
|
||||
|
|
|
@ -12,6 +12,7 @@ def pendulum_vector_field(point, mu=0.1, g=9.8, L=3):
|
|||
|
||||
# Scenes
|
||||
|
||||
|
||||
class VectorFieldTest(Scene):
|
||||
def construct(self):
|
||||
plane = NumberPlane(
|
||||
|
@ -43,6 +44,83 @@ class VectorFieldTest(Scene):
|
|||
self.wait(10)
|
||||
|
||||
|
||||
class FormulasAreLies(PiCreatureScene):
|
||||
def construct(self):
|
||||
morty = self.pi_creature
|
||||
t2c = {
|
||||
"{L}": BLUE,
|
||||
"{g}": YELLOW,
|
||||
"\\theta_0": WHITE,
|
||||
"\\sqrt{\\,": WHITE,
|
||||
}
|
||||
kwargs = {"tex_to_color_map": t2c}
|
||||
period_eq = TexMobject(
|
||||
"\\text{Period} = 2\\pi \\sqrt{\\,{L} / {g}}",
|
||||
**kwargs
|
||||
)
|
||||
theta_eq = TexMobject(
|
||||
"\\theta(t) = \\theta_0 \\cos\\left("
|
||||
"\\sqrt{\\,{L} / {g}} \\cdot t"
|
||||
"\\right)",
|
||||
**kwargs
|
||||
)
|
||||
equations = VGroup(theta_eq, period_eq)
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
|
||||
for eq in period_eq, theta_eq:
|
||||
i = eq.index_of_part_by_tex("\\sqrt")
|
||||
eq.sqrt_part = eq[i:i + 4]
|
||||
|
||||
theta0 = theta_eq.get_part_by_tex("\\theta_0")
|
||||
theta0_words = TextMobject("Starting angle")
|
||||
theta0_words.next_to(theta0, UL)
|
||||
theta0_words.shift(UP + 0.5 * RIGHT)
|
||||
arrow = Arrow(
|
||||
theta0_words.get_bottom(),
|
||||
theta0,
|
||||
color=WHITE,
|
||||
tip_length=0.25,
|
||||
)
|
||||
|
||||
bubble = SpeechBubble()
|
||||
bubble.pin_to(morty)
|
||||
bubble.write("Lies!")
|
||||
bubble.content.scale(2)
|
||||
bubble.resize_to_content()
|
||||
|
||||
self.add(period_eq)
|
||||
morty.change("pondering", period_eq)
|
||||
self.wait()
|
||||
theta_eq.remove(*theta_eq.sqrt_part)
|
||||
self.play(
|
||||
TransformFromCopy(
|
||||
period_eq.sqrt_part,
|
||||
theta_eq.sqrt_part,
|
||||
),
|
||||
FadeIn(theta_eq)
|
||||
)
|
||||
theta_eq.add(*theta_eq.sqrt_part)
|
||||
self.play(
|
||||
FadeInFrom(theta0_words, LEFT),
|
||||
GrowArrow(arrow),
|
||||
)
|
||||
self.wait()
|
||||
self.play(morty.change, "confused")
|
||||
self.wait(0)
|
||||
self.play(
|
||||
morty.change, "angry",
|
||||
ShowCreation(bubble),
|
||||
FadeInFromPoint(bubble.content, morty.mouth),
|
||||
equations.to_edge, LEFT,
|
||||
FadeOut(arrow),
|
||||
FadeOut(theta0_words),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def create_pi_creature(self):
|
||||
return Mortimer().to_corner(DR)
|
||||
|
||||
|
||||
class NewSceneName(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
|
Loading…
Add table
Reference in a new issue