ThreeFilters of waves

This commit is contained in:
Grant Sanderson
2017-09-11 06:52:15 -07:00
parent 12dcb7a3ea
commit 86b9e629e0
5 changed files with 824 additions and 65 deletions

43
bell.py
View File

@ -48,10 +48,14 @@ class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarizationScene):
"start_theta" : -0.9*np.pi,
"target_theta" : -0.6*np.pi,
"apply_filter" : True,
"lower_portion_shift" : 3*IN
"lower_portion_shift" : 3*IN,
"show_M_vects" : True,
}
def setup(self):
DirectionOfPolarizationScene.setup(self)
if not self.show_M_vects:
for M_vect in self.em_wave.M_vects:
M_vect.set_fill(opacity = 0)
self.continual_update()
for vect in it.chain(self.em_wave.E_vects, self.em_wave.M_vects):
vect.reset_normal_vector()
@ -64,9 +68,9 @@ class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarizationScene):
lower_filter.save_state()
pol_filter.remove(pol_filter.label)
passing_words = TextMobject("Photon", "passes through")
passing_words = TextMobject("Photon", "passes through\\\\", "entirely")
passing_words.highlight(GREEN)
filtered_words = TextMobject("Photon", "is blocked")
filtered_words = TextMobject("Photon", "is blocked\\\\", "entirely")
filtered_words.highlight(RED)
for words in passing_words, filtered_words:
words.next_to(ORIGIN, UP+LEFT)
@ -114,7 +118,7 @@ class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarizationScene):
rate_func = squish_rate_func(there_and_back, 0.4, 0.6),
run_time = filtered_photon.run_time
)
for x in range(3):
for x in range(4):
self.play(
passing_photon,
filtered_photon,
@ -123,6 +127,11 @@ class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarizationScene):
)
self.dither()
class PhotonPassesCompletelyOrNotAtAllForWavesVideo(PhotonPassesCompletelyOrNotAtAll):
CONFIG = {
"show_M_vects" : False,
}
class DirectionOfPolarization(DirectionOfPolarizationScene):
def construct(self):
self.remove(self.pol_filter)
@ -197,8 +206,8 @@ class PhotonsThroughPerpendicularFilters(PhotonPassesCompletelyOrNotAtAll):
def shoot_photon(self, *added_anims):
photon = self.get_photons()[1]
pol_filter = self.pol_filters[0]
absorbtion = self.get_filter_absorbtion_animation(pol_filter, photon)
self.play(photon, absorbtion)
absorption = self.get_filter_absorption_animation(pol_filter, photon)
self.play(photon, absorption)
def get_photons(self):
@ -533,7 +542,7 @@ class BasicsOfPolarization(DirectionOfPolarizationScene):
[passing_photon],
[
filtered_photon,
self.get_filter_absorbtion_animation(
self.get_filter_absorption_animation(
self.pol_filter,
filtered_photon
)
@ -663,11 +672,11 @@ class ShowVariousFilterPairsWithPhotonsOverTime(PhotonsThroughPerpendicularFilte
blocked_photon.rate_func = squish_rate_func(
lambda x : x, 0, 0.5,
)
first_absorbtion = self.get_filter_absorbtion_animation(
first_absorption = self.get_filter_absorption_animation(
self.pol_filters[0], blocked_photon
)
first_absorbtion.rate_func = squish_rate_func(
first_absorbtion.rate_func, 0, 0.5,
first_absorption.rate_func = squish_rate_func(
first_absorption.rate_func, 0, 0.5,
)
photons = [
@ -681,16 +690,16 @@ class ShowVariousFilterPairsWithPhotonsOverTime(PhotonsThroughPerpendicularFilte
)
added_anims = []
if photon.filter_distance == SPACE_WIDTH + 2:
absorbtion = self.get_filter_absorbtion_animation(
absorption = self.get_filter_absorption_animation(
self.second_filter, photon
)
absorbtion.rate_func = squish_rate_func(
absorbtion.rate_func, 0.5, 1
absorption.rate_func = squish_rate_func(
absorption.rate_func, 0.5, 1
)
added_anims.append(absorbtion)
added_anims.append(absorption)
self.play(
blocked_photon,
first_absorbtion,
first_absorption,
photon,
*added_anims
)
@ -721,11 +730,11 @@ class ShowVariousFilterPairs(ShowVariousFilterPairsWithPhotonsOverTime):
"filter_z_coordinates" : [2.5, 0, -2.5],
"angles" : [0, np.pi/4, np.pi/2],
"n_lines" : 20,
"line_start_length" : 16,
"line_end_length" : 16,
"new_group_shift_val" : 2.5*IN,
"prev_group_shift_val" : 1.75*IN,
"ambient_rotation_rate" : 0.015,
"line_start_length" : 16,
"line_end_length" : 16,
"lines_depth" : 1.2,
"lines_shift_vect" : SMALL_BUFF*OUT,
}

View File

@ -478,6 +478,14 @@ def there_and_back(t, inflection = 10.0):
new_t = 2*t if t < 0.5 else 2*(1 - t)
return smooth(new_t, inflection)
def there_and_back_with_pause(t):
if t < 1./3:
return smooth(3*t)
elif t < 2./3:
return 1
else:
return smooth(3 - 3*t)
def running_start(t, pull_factor = -0.5):
return bezier([0, 0, pull_factor, pull_factor, 1, 1, 1])(t)

View File

@ -91,7 +91,6 @@ class TexMobject(SVGMobject):
len(tex) > len(t1) and tex[len(t1)] in "()[]\\"
])
if should_replace:
print len(t1)
tex = tex.replace(t1, "\\big")
if tex == "":
tex = "\\quad"

View File

@ -108,7 +108,10 @@ class Scene(object):
if "include_submobjects" not in kwargs:
kwargs["include_submobjects"] = False
if mobjects is None:
mobjects = self.mobjects
mobjects = list_update(
self.foreground_mobjects,
self.mobjects,
)
if background is not None:
self.set_camera_image(background)
else:

832
waves.py
View File

@ -21,6 +21,7 @@ from topics.three_dimensions import *
from topics.objects import *
from topics.probability import *
from topics.complex_numbers import *
from topics.common_scenes import *
from scene import Scene
from scene.reconfigurable_scene import ReconfigurableScene
from scene.zoomed_scene import *
@ -28,7 +29,6 @@ from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
E_COLOR = BLUE
M_COLOR = YELLOW
@ -205,6 +205,7 @@ class WavePacket(Animation):
"filter_distance" : SPACE_WIDTH,
"get_filtered" : False,
"remover" : True,
"width" : 2*np.pi,
}
def __init__(self, **kwargs):
digest_config(self, kwargs)
@ -246,11 +247,17 @@ class WavePacket(Animation):
distance_from_start = np.linalg.norm(tail - em_wave.start_point)
if self.get_filtered and distance_from_start > self.filter_distance:
A = 0
epsilon = 0.05
if abs(A) < epsilon:
A = 0
vect.restore()
if vect.get_length() < epsilon:
pass
vect.scale(A/vect.get_length(), about_point = tail)
def E_func(self, x):
return np.sin(x)*np.exp(-0.25*x*x)
x0 = 2*np.pi*x/self.width
return np.sin(x0)*np.exp(-0.25*x0*x0)
class FilterLabel(TexMobject):
def __init__(self, tex, degrees, **kwargs):
@ -333,7 +340,7 @@ class FilterScene(ThreeDScene):
if self.ambient_rotation_rate > 0:
self.begin_ambient_camera_rotation(self.ambient_rotation_rate)
def get_filter_absorbtion_animation(self, pol_filter, photon):
def get_filter_absorption_animation(self, pol_filter, photon):
x = pol_filter.get_center()[0]
alpha = (x + SPACE_WIDTH) / (2*SPACE_WIDTH)
return ApplyMethod(
@ -351,6 +358,7 @@ class DirectionOfPolarizationScene(FilterScene):
"target_phi" : 0.9*np.pi/2,
"ambient_rotation_rate" : 0.005,
"apply_filter" : False,
"quantum" : False,
}
def setup(self):
self.reference_line = Line(ORIGIN, RIGHT)
@ -408,23 +416,21 @@ class DirectionOfPolarizationScene(FilterScene):
for pol_filter in filters:
filter_x = pol_filter.arrow.get_center()[0]
for vect_group, angle in zip(vect_groups, [0, -np.pi/2]):
proj_vect = rotate_vector(
OUT, pol_filter.filter_angle + angle, RIGHT,
)
proj_matrix = np.array([RIGHT] + [
proj_vect*np.dot(proj_vect, basis)
for basis in UP, OUT
]).T
for vect in vect_group:
start, end = vect.get_start_and_end()
target_angle = pol_filter.filter_angle + angle
for vect_mob in vect_group:
vect = vect_mob.get_vector()
vect_angle = angle_of_vector([
vect[2], -vect[1]
])
angle_diff = target_angle - vect_angle
start, end = vect_mob.get_start_and_end()
if start[0] > filter_x:
vect.apply_matrix(proj_matrix)
vect.shift(start - vect.get_start())
vect.set_tip_points(vect.tip)
vect.set_rectangular_stem_points()
vect_mob.rotate(angle_diff, RIGHT)
if not self.quantum:
vect_mob.scale(np.cos(angle_diff))
def update_rectangles(self):
if self.rectangles not in self.mobjects:
if not hasattr(self, "rectangles") or self.rectangles not in self.mobjects:
return
r1, r2 = self.rectangles
@ -445,6 +451,43 @@ class DirectionOfPolarizationScene(FilterScene):
################
class AskWhatsDifferentInQM(TeacherStudentsScene):
def construct(self):
self.student_says(
"What's different in \\\\ quantum mechanics?"
)
self.play(self.teacher.change, "pondering")
self.dither(3)
class VideoWrapper(Scene):
CONFIG = {
"title" : ""
}
def construct(self):
title = TextMobject(self.title)
title.to_edge(UP)
self.add(title)
rect = ScreenRectangle()
rect.scale_to_fit_height(6)
rect.next_to(title, DOWN)
self.add(rect)
self.dither()
class BellsWrapper(VideoWrapper):
CONFIG = {
"title" : "Bell's inequalities"
}
class FromOtherVideoWrapper(VideoWrapper):
CONFIG = {
"title" : "See the other video..."
}
class OriginOfQuantumMechanicsWrapper(VideoWrapper):
CONFIG = {
"title" : "The origin of quantum mechanics"
}
class IntroduceElectricField(PiCreatureScene):
CONFIG = {
"vector_field_colors" : [BLUE_B, BLUE_D],
@ -2138,9 +2181,10 @@ class EnergyOfWavesWavePortion(DirectWaveOutOfScreen):
self.v_wave = v_wave
def scale_up_and_down(self):
for scale_factor in 1.25, 0.4, 1.5, 0.5:
for scale_factor in 1.25, 0.4, 1.5, 0.3, 2:
self.scale_wave(scale_factor)
self.dither()
self.dither(4)
######
@ -2266,6 +2310,10 @@ class EnergyOfWavesTeacherPortion(TeacherStudentsScene):
self.dither(5)
class DescribePhoton(ThreeDScene):
CONFIG = {
"x_color" : RED,
"y_color" : GREEN,
}
def setup(self):
self.axes = ThreeDAxes()
self.add(self.axes)
@ -2292,20 +2340,19 @@ class DescribePhoton(ThreeDScene):
self.em_wave = em_wave
def construct(self):
self.force_skipping()
self.add_ket_equation()
self.shoot_a_few_photons()
self.freeze_photon()
self.reposition_to_face_photon_head_on()
self.show_components()
self.change_basis()
self.show_amplitude_and_phase()
self.change_basis()
self.write_different_meaning()
self.write_components()
self.describe_via_energy()
self.components_not_possible_in_isolation()
self.ask_what_they_mean()
self.change_camera()
def add_ket_equation(self):
equation = TexMobject(
@ -2314,10 +2361,10 @@ class DescribePhoton(ThreeDScene):
"\\alpha", "|\\!\\rightarrow \\rangle", "+",
"\\beta", "|\\!\\uparrow \\rangle",
)
equation.to_edge(UP).shift(MED_SMALL_BUFF*RIGHT)
equation.to_edge(UP)
equation.highlight_by_tex("psi", E_COLOR)
equation.highlight_by_tex("alpha", GREEN)
equation.highlight_by_tex("beta", RED)
equation.highlight_by_tex("alpha", self.x_color)
equation.highlight_by_tex("beta", self.y_color)
rect = SurroundingRectangle(equation.get_part_by_tex("psi"))
rect.highlight(E_COLOR)
words = TextMobject("Polarization\\\\", "state")
@ -2337,6 +2384,7 @@ class DescribePhoton(ThreeDScene):
self.add(equation)
self.equation = equation
self.superposition = VGroup(*equation[1][2:])
def shoot_a_few_photons(self):
for x in range(2):
@ -2345,7 +2393,7 @@ class DescribePhoton(ThreeDScene):
def freeze_photon(self):
self.play(
self.photon,
rate_func = lambda x : 0.5*x,
rate_func = lambda x : 0.55*x,
run_time = 1
)
self.add(self.photon.mobject)
@ -2385,7 +2433,7 @@ class DescribePhoton(ThreeDScene):
color = color,
normal_vector = RIGHT,
)
for color, direction in (GREEN, UP), (RED, OUT)
for color, direction in (self.x_color, UP), (self.y_color, OUT)
]
v_arrow.move_to(h_arrow.get_end(), IN)
h_part = VGroup(*self.equation[1][2:4]).copy()
@ -2418,7 +2466,7 @@ class DescribePhoton(ThreeDScene):
new_alpha = alpha.copy().shift(IN)
rhs = TexMobject(
"=", "A_x", "e",
"^{2\\pi", "f", "t", "+", "\\phi_x }"
"^{i", "(2\\pi", "f", "t", "+", "\\phi_x)}"
)
A_rect = SurroundingRectangle(rhs.get_part_by_tex("A_x"), buff = 0.5*SMALL_BUFF)
A_word = TextMobject("Amplitude")
@ -2426,7 +2474,7 @@ class DescribePhoton(ThreeDScene):
A_word.next_to(A_rect, DOWN, aligned_edge = LEFT)
A_group = VGroup(A_rect, A_word)
A_group.highlight(YELLOW)
phase_rect = SurroundingRectangle(VGroup(*rhs[3:]), buff = 0.5*SMALL_BUFF)
phase_rect = SurroundingRectangle(VGroup(*rhs[4:]), buff = 0.5*SMALL_BUFF)
phase_word = TextMobject("Phase")
phase_word.add_background_rectangle()
phase_word.next_to(phase_rect, UP)
@ -2452,7 +2500,7 @@ class DescribePhoton(ThreeDScene):
self.play(*map(FadeOut, [new_alpha, group]))
def change_basis(self):
superposition = VGroup(*self.equation[1][2:])
superposition = self.superposition
plane = self.xy_plane
h_arrow = self.h_arrow
v_arrow = self.v_arrow
@ -2513,40 +2561,732 @@ class DescribePhoton(ThreeDScene):
self.equation.generate_target()
self.revert_to_original_skipping_status()
self.play(*map(MoveToTarget, movers))
self.dither(2)
self.play(*[mob.restore for mob in movers])
self.dither()
def write_different_meaning(self):
pass
superposition = self.superposition
superposition.rotate(np.pi/2, DOWN)
rect = SurroundingRectangle(superposition)
VGroup(superposition, rect).rotate(np.pi/2, UP)
morty = Mortimer(mode = "confused")
blinked = morty.copy().blink()
words = TextMobject("Means something \\\\ different...")
for mob in morty, blinked, words:
mob.rotate(np.pi/2, RIGHT)
mob.rotate(np.pi/2, OUT)
words.next_to(rect, UP)
VGroup(morty, blinked).next_to(words, IN)
self.play(
ShowCreation(rect),
Write(words, run_time = 2)
)
self.play(FadeIn(morty))
self.play(Transform(
morty, blinked,
rate_func = squish_rate_func(there_and_back)
))
self.dither()
self.play(*map(FadeOut, [
morty, words, rect,
self.equation.rect,
self.equation.words,
]))
def write_components(self):
pass
d_brace = Brace(Line(ORIGIN, 2*RIGHT), UP, buff = SMALL_BUFF)
h_brace = Brace(Line(ORIGIN, (2/np.sqrt(2))*RIGHT), DOWN, buff = SMALL_BUFF)
v_brace = Brace(Line(ORIGIN, (2/np.sqrt(2))*UP), RIGHT, buff = SMALL_BUFF)
d_brace.rotate(np.pi/4)
v_brace.shift((2/np.sqrt(2))*RIGHT)
braces = VGroup(d_brace, h_brace, v_brace)
group = VGroup(braces)
tex = ["1"] + 2*["\\sqrt{1/2}"]
colors = BLUE, self.x_color, self.y_color
for brace, tex, color in zip(braces, tex, colors):
brace.label = brace.get_tex(tex, buff = SMALL_BUFF)
brace.label.add_background_rectangle()
brace.label.highlight(color)
group.add(brace.label)
group.rotate(np.pi/2, RIGHT)
group.rotate(np.pi/2, OUT)
self.play(
GrowFromCenter(d_brace),
Write(d_brace.label)
)
self.dither()
self.play(
FadeOut(self.h_part_tex),
FadeOut(self.v_part_tex),
GrowFromCenter(h_brace),
GrowFromCenter(v_brace),
)
self.play(
Write(h_brace.label),
Write(v_brace.label),
)
self.dither()
self.d_brace = d_brace
self.h_brace = h_brace
self.v_brace = v_brace
def describe_via_energy(self):
pass
energy = TexMobject(
"&\\text{Energy}",
"=", "(hf)", "(", "1", ")^2\\\\",
"&=", "(hf)", "\\left(", "\\sqrt{1/2}", "\\right)^2",
"+", "(hf)", "\\left(", "\\sqrt{1/2}", "\\right)^2",
)
energy.scale(0.8)
one = energy.get_part_by_tex("1", substring = False)
one.highlight(BLUE)
halves = energy.get_parts_by_tex("1/2")
halves[0].highlight(self.x_color)
halves[1].highlight(self.y_color)
indices = [0, 3, 6, len(energy)]
parts = VGroup(*[
VGroup(*energy[i1:i2])
for i1, i2 in zip(indices, indices[1:])
])
for part in parts:
bg_rect = BackgroundRectangle(part)
bg_rect.stretch_in_place(1.5, 1)
part.add_to_back(bg_rect)
parts.to_corner(UP+LEFT, buff = MED_SMALL_BUFF)
parts.shift(DOWN)
parts.rotate(np.pi/2, RIGHT)
parts.rotate(np.pi/2, OUT)
self.play(Write(parts[0]), run_time = 2)
self.play(Indicate(energy.get_part_by_tex("hf")))
self.play(
Transform(
self.d_brace.label.copy(),
one.copy(),
remover = True
),
Write(parts[1], run_time = 1),
)
self.dither()
self.play(
Transform(
self.h_brace.label[1].copy(),
halves[0].copy(),
remover = True,
rate_func = squish_rate_func(smooth, 0, 0.75)
),
Transform(
self.v_brace.label[1].copy(),
halves[1].copy(),
remover = True,
rate_func = squish_rate_func(smooth, 0.25, 1)
),
Write(parts[2]),
run_time = 2
)
self.dither()
self.energy_equation_parts = parts
def components_not_possible_in_isolation(self):
pass
half_hf = VGroup(*self.energy_equation_parts[2][1:6])
half_hf.rotate(np.pi/2, DOWN)
rect = SurroundingRectangle(half_hf)
VGroup(half_hf, rect).rotate(np.pi/2, UP)
randy = Randolph()
randy.scale(0.7)
randy.look(UP)
randy.rotate(np.pi/2, RIGHT)
randy.rotate(np.pi/2, OUT)
randy.next_to(rect, IN)
self.play(
ShowCreation(rect),
FadeIn(randy)
)
self.play(
randy.rotate, np.pi/2, IN,
randy.rotate, np.pi/2, LEFT,
randy.change, "maybe",
randy.rotate, np.pi/2, RIGHT,
randy.rotate, np.pi/2, OUT,
)
self.dither()
def ask_what_they_mean(self):
pass
morty = Mortimer(mode = "confused")
morty.scale(0.7)
morty.to_edge(LEFT)
bubble = morty.get_bubble()
bubble.write("?!?")
bubble.resize_to_content()
bubble.add(bubble.content)
bubble.pin_to(morty)
class SuperpositionHasDifferentInterpretation(TeacherStudentsScene):
group = VGroup(morty, bubble)
group.to_corner(DOWN+RIGHT)
group.rotate(np.pi/2, RIGHT)
group.rotate(np.pi/2, OUT)
component = VGroup(self.h_arrow, self.h_brace, self.h_brace.label)
self.play(
FadeIn(morty),
component.next_to, morty, DOWN, OUT,
component.shift, MED_LARGE_BUFF*(DOWN + OUT),
)
component.rotate(np.pi/2, DOWN)
cross = Cross(component)
VGroup(component, cross).rotate(np.pi/2, UP)
cross.highlight("#ff0000")
self.play(ShowCreation(cross))
bubble.remove(bubble.content)
self.play(
ShowCreation(bubble),
Write(bubble.content),
morty.look_at, component,
)
self.dither()
def change_camera(self):
everything = VGroup(*self.get_top_level_mobjects())
everything.remove(self.photon.mobject)
everything.remove(self.axes)
self.play(*map(FadeOut, everything))
self.move_camera(
phi = 0.8*np.pi/2,
theta = -0.3*np.pi,
run_time = 2
)
self.play(
self.photon,
rate_func = lambda x : min(x + 0.55, 1),
run_time = 2,
)
self.photon.rate_func = lambda x : x
self.play(self.photon)
self.dither()
class GetExperimental(TeacherStudentsScene):
def construct(self):
pass
self.teacher_says("Get experimental!", target_mode = "hooray")
self.change_student_modes(*["hooray"]*3)
self.dither(3)
class ShootPhotonThroughFilter(DirectionOfPolarizationScene):
CONFIG = {
"EMWave_config" : {
"wave_number" : 0,
"A_vect" : [0, 1, 1],
"start_point" : SPACE_WIDTH*LEFT,
"amplitude" : np.sqrt(2),
},
"pol_filter_configs" : [{
"label_tex" : "\\text{Filter}",
"include_arrow_label" : False,
}],
"apply_filter" : True,
"quantum" : True,
"pre_filter_alpha" : 0.35,
"ambient_rotation_rate" : 0,
}
def setup(self):
DirectionOfPolarizationScene.setup(self)
self.em_wave.update(0)
self.remove(self.em_wave)
def construct(self):
self.add_superposition_tex()
self.ask_what_would_happen()
self.expect_half_energy_to_be_absorbed()
self.probabalistic_passing_and_blocking()
self.note_change_in_polarization()
def add_superposition_tex(self):
superposition_tex = TexMobject(
"|\\!\\nearrow\\rangle",
"=",
"(\\sqrt{1/2})", "|\\!\\rightarrow \\rangle", "+",
"(\\sqrt{1/2})", "|\\!\\uparrow \\rangle",
)
superposition_tex.scale(0.9)
superposition_tex[0].highlight(E_COLOR)
halves = superposition_tex.get_parts_by_tex("1/2")
for half, color in zip(halves, [RED, GREEN]):
half.highlight(color)
h_rect = SurroundingRectangle(VGroup(*superposition_tex[2:4]))
v_rect = SurroundingRectangle(VGroup(*superposition_tex[5:7]))
VGroup(h_rect, v_rect).fade(1)
superposition_tex.h_rect = h_rect
superposition_tex.v_rect = v_rect
superposition_tex.add(h_rect, v_rect)
superposition_tex.next_to(ORIGIN, LEFT)
superposition_tex.to_edge(UP)
superposition_tex.rotate(np.pi/2, RIGHT)
self.superposition_tex = superposition_tex
def ask_what_would_happen(self):
photon = self.get_photon(
rate_func = lambda t : self.pre_filter_alpha*t,
remover = False,
run_time = 0.6,
)
question = TextMobject("What's going to happen?")
question.add_background_rectangle()
question.highlight(YELLOW)
question.rotate(np.pi/2, RIGHT)
question.next_to(self.superposition_tex, IN)
self.pol_filter.add(
self.pol_filter.arrow.copy().rotate(np.pi/2, OUT)
)
self.pol_filter.save_state()
self.pol_filter.shift(5*OUT)
self.set_camera_position(theta = -0.9*np.pi)
self.play(self.pol_filter.restore)
self.move_camera(
theta = -0.6*np.pi,
)
self.play(
photon,
FadeIn(self.superposition_tex)
)
self.play(Write(question, run_time = 1))
self.dither()
self.play(FadeOut(self.pol_filter.label))
self.pol_filter.remove(self.pol_filter.label)
self.add(self.pol_filter)
self.question = question
self.frozen_photon = photon
def expect_half_energy_to_be_absorbed(self):
words = TextMobject("Absorbs horizontal \\\\ energy")
words.highlight(RED)
words.next_to(ORIGIN, UP+RIGHT, MED_LARGE_BUFF)
words.rotate(np.pi/2, RIGHT)
words.rotate(np.pi/2, OUT)
lines = VGroup(*[
Line(
np.sin(a)*RIGHT + np.cos(a)*UP,
np.sin(a)*LEFT + np.cos(a)*UP,
color = RED,
stroke_width = 2,
)
for a in np.linspace(0, np.pi, 15)
])
lines.rotate(np.pi/2, RIGHT)
lines.rotate(np.pi/2, OUT)
self.move_camera(
phi = np.pi/2, theta = 0,
added_anims = [
Rotate(self.superposition_tex, np.pi/2),
] + [
ApplyMethod(
v.rotate_in_place,
-np.pi/2,
method_kwargs = {"axis" : v.get_vector()}
)
for v in self.frozen_photon.mobject
]
)
self.play(
Write(words, run_time = 2),
self.superposition_tex.h_rect.set_stroke, RED, 3,
*map(GrowFromCenter, lines)+\
[
Animation(self.pol_filter),
Animation(self.frozen_photon.mobject)
]
)
self.dither(2)
self.move_camera(
phi = 0.8*np.pi/2, theta = -0.7*np.pi,
added_anims = [
FadeOut(words),
Animation(lines),
Rotate(self.superposition_tex, -np.pi/2),
] + [
ApplyMethod(
v.rotate_in_place,
np.pi/2,
method_kwargs = {"axis" : v.get_vector()}
)
for v in self.frozen_photon.mobject
]
)
self.play(
FadeOut(lines),
FadeOut(self.question),
self.superposition_tex.h_rect.fade, 1,
Animation(self.pol_filter)
)
self.dither()
self.absorption_words = words
def probabalistic_passing_and_blocking(self):
absorption = self.get_filter_absorption_animation(
self.pol_filter, self.get_blocked_photon()
)
prob = TexMobject("P(", "\\text{pass}", ")", "=", "1/2")
prob.highlight_by_tex("pass", GREEN)
prob.rotate(np.pi/2, RIGHT)
prob.next_to(self.superposition_tex, IN, MED_SMALL_BUFF, RIGHT)
self.remove(self.frozen_photon.mobject)
self.play(
self.get_photon(),
rate_func = lambda t : min(t+self.pre_filter_alpha, 1),
)
self.play(
FadeIn(prob),
self.get_blocked_photon(),
absorption
)
bools = 4*[True] + 4*[False]
random.shuffle(bools)
for should_pass in bools:
if should_pass:
self.play(self.get_photon(), run_time = 1)
else:
self.play(
self.get_blocked_photon(),
Animation(self.axes),
absorption,
run_time = 1
)
self.play(FadeOut(prob))
def note_change_in_polarization(self):
words = TextMobject(
"``Collapses'' \\\\ from", "$|\\!\\nearrow\\rangle$",
"to", "$|\\!\\uparrow\\rangle$"
)
words.highlight_by_tex("nearrow", E_COLOR)
words.highlight_by_tex("uparrow", GREEN)
words.next_to(ORIGIN, RIGHT, MED_LARGE_BUFF)
words.shift(2*UP)
words.rotate(np.pi/2, RIGHT)
photon = self.get_photon(run_time = 4)
for vect in photon.mobject:
if vect.get_center()[0] > 0:
vect.saved_state.set_fill(GREEN)
self.play(FadeIn(words), photon)
for x in range(3):
self.play(photon)
######
def get_photon(self, **kwargs):
kwargs["run_time"] = kwargs.get("run_time", 1)
kwargs["include_M_vects"] = False
return WavePacket(em_wave = self.em_wave.copy(), **kwargs)
def get_blocked_photon(self, **kwargs):
return self.get_photon(self, get_filtered = True, **kwargs)
class PhotonPassesCompletelyOrNotAtAllStub(ExternallyAnimatedScene):
pass
class ThreeFilters(ShootPhotonThroughFilter):
CONFIG = {
"filter_x_coordinates" : [-4, 0, 4],
"pol_filter_configs" : [
{"filter_angle" : 0},
{"filter_angle" : np.pi/4},
{"filter_angle" : np.pi/2},
],
"EMWave_config" : {
"A_vect" : [0, 0, 1],
"amplitude" : 1.5,
"n_vectors" : 60,
},
"line_start_length" : 8,
"line_end_length" : 8,
"n_lines" : 20,
"lines_depth" : 1.8,
"lines_shift_vect" : SMALL_BUFF*OUT,
"random_seed" : 6,
}
def construct(self):
self.remove(self.axes)
self.setup_filters()
self.setup_lines()
self.setup_arrows()
self.fifty_percent_pass_second()
self.show_changed_to_diagonal()
self.fifty_percent_to_pass_third()
self.show_lines_with_middle()
self.remove_middle_then_put_back()
def setup_filters(self):
for pf in self.pol_filters:
pf.arrow_label.rotate(np.pi/2, OUT)
pf.arrow_label.next_to(pf.arrow, RIGHT)
pf.arrow_label.rotate(np.pi/2, LEFT)
pf.arrow_label.add_background_rectangle()
pf.arrow_label.rotate(np.pi/2, RIGHT)
self.add_foreground_mobject(pf.arrow_label)
def setup_lines(self):
lines_group = VGroup(*[
self.get_lines(pf1, pf2, ratio)
for pf1, pf2, ratio in zip(
[None] + list(self.pol_filters),
list(self.pol_filters) + [None],
[1, 1, 0.5, 0.25]
)
])
lines = lines_group[0]
spacing = lines[1].get_start() - lines[0].get_start()
lines.add(lines.copy().shift(spacing/2))
self.lines_group = lines_group
self.A_to_C_lines = self.get_lines(
self.pol_filters[0], self.pol_filters[2],
)
def setup_arrows(self):
for E_vect in self.em_wave.E_vects:
E_vect.normal_vector = IN+DOWN
self.em_wave.update(0)
def fifty_percent_pass_second(self):
arrow = Arrow(
ORIGIN, 3*RIGHT,
use_rectangular_stem = False,
path_arc = -0.8*np.pi
)
label = TexMobject("50\\%")
label.next_to(arrow, UP)
group = VGroup(arrow, label)
group.rotate(np.pi/2, RIGHT)
group.next_to(self.pol_filters[1], OUT, buff = 0)
group.highlight(BLUE)
l1, l2, l3 = self.lines_group[:3]
pf1, pf2, pf3 = self.pol_filters
kwargs = {
"submobject_mode" : "all_at_once",
"rate_func" : None,
}
self.play(ShowCreation(l1, run_time = 1, **kwargs))
self.play(
ShowCreation(l2, **kwargs),
Animation(VGroup(pf1, l1)),
ShowCreation(arrow),
run_time = 0.5,
)
self.play(
ShowCreation(l3, **kwargs),
Animation(VGroup(pf2, l2, pf1, l1)),
FadeIn(label),
run_time = 0.5,
)
self.dither(2)
self.play(
FadeOut(l3),
Animation(pf2),
FadeOut(l2),
Animation(pf1),
FadeOut(l1)
)
self.fifty_percent_arrow_group = group
def show_changed_to_diagonal(self):
photon = self.get_photon(
run_time = 2,
rate_func = lambda x : 0.6*x,
remover = False,
)
brace = Brace(Line(1.5*LEFT, 1.5*RIGHT), DOWN)
label = brace.get_text(
"Changed to",
"$|\\!\\nearrow\\rangle$"
)
label.highlight_by_tex("rangle", BLUE)
group = VGroup(brace, label)
group.rotate(np.pi/2, RIGHT)
group.shift(2*RIGHT + 0.5*IN)
self.play(photon)
self.play(
GrowFromCenter(brace),
Write(label, run_time = 1)
)
kwargs = {
"run_time" : 3,
"rate_func" : there_and_back_with_pause,
}
self.move_camera(
phi = np.pi/2,
theta = 0,
added_anims = [
Rotate(
v, np.pi/2,
axis = v.get_vector(),
in_place = True,
**kwargs
)
for v in photon.mobject
] + [
Rotate(
label, np.pi/2,
axis = OUT,
in_place = True,
**kwargs
),
],
**kwargs
)
self.dither()
self.photon = photon
self.brace_group = VGroup(brace, label)
def fifty_percent_to_pass_third(self):
arrow_group = self.fifty_percent_arrow_group.copy()
arrow_group.shift(4*RIGHT)
arrow, label = arrow_group
a = self.photon.rate_func(1)
new_photon = self.get_photon(
rate_func = lambda x : (1-a)*x + a,
run_time = 1
)
self.revert_to_original_skipping_status()
self.play(
ShowCreation(arrow),
Write(label, run_time = 1)
)
self.remove(self.photon.mobject)
self.play(new_photon)
self.second_fifty_percent_arrow_group = arrow_group
def show_lines_with_middle(self):
l1, l2, l3, l4 = self.lines_group
pf1, pf2, pf3 = self.pol_filters
self.play(
FadeIn(l4),
Animation(pf3),
FadeIn(l3),
Animation(pf2),
FadeIn(l2),
Animation(pf1),
FadeIn(l1),
FadeOut(self.brace_group)
)
self.dither(2)
def remove_middle_then_put_back(self):
l1, l2, l3, l4 = self.lines_group
pf1, pf2, pf3 = self.pol_filters
mid_lines = self.A_to_C_lines
mover = VGroup(
pf2,
self.fifty_percent_arrow_group,
self.second_fifty_percent_arrow_group,
)
arrow = Arrow(
ORIGIN, 7*RIGHT,
use_rectangular_stem = False,
path_arc = 0.5*np.pi,
)
labels = VGroup(*map(TexMobject, ["0\\%", "25\\%"]))
labels.scale(1.5)
labels.next_to(arrow, DOWN)
group = VGroup(arrow, labels)
group.rotate(np.pi/2, RIGHT)
group.shift(2*LEFT + IN)
group.highlight(GREEN)
self.remove(l2, l3)
self.play(
FadeOut(l4),
Animation(pf3),
FadeOut(l3),
ApplyMethod(
mover.shift, 3*OUT,
rate_func = running_start
),
ReplacementTransform(l2.copy(), mid_lines),
Animation(pf1),
Animation(l1)
)
self.play(
ShowCreation(arrow),
Write(labels[0], run_time = 1)
)
self.dither(2)
self.play(
FadeIn(l4),
Animation(pf3),
FadeOut(mid_lines),
FadeIn(l3),
mover.shift, 3*IN,
FadeIn(l2),
Animation(pf1),
Animation(l1)
)
self.play(ReplacementTransform(*labels))
self.dither(3)
####
def get_photon(self, **kwargs):
return ShootPhotonThroughFilter.get_photon(self, width = 4, **kwargs)
def get_lines(self, filter1 = None, filter2 = None, ratio = 1.0):
n = self.n_lines
start, end = [
(f.point_from_proportion(0.75) if f is not None else None)
for f in filter1, filter2
]
if start is None:
start = end + self.line_start_length*LEFT
if end is None:
end = start + self.line_end_length*RIGHT
nudge = (float(self.lines_depth)/self.n_lines)*OUT
lines = VGroup(*[
Line(start, end).shift(z*nudge)
for z in range(n)
])
lines.set_stroke(YELLOW, 2)
lines.move_to(start, IN+LEFT)
lines.shift(self.lines_shift_vect)
n_to_block = int((1-ratio)*self.n_lines)
random.seed(self.random_seed)
indices_to_block = random.sample(
range(self.n_lines), n_to_block
)
VGroup(*[lines[i] for i in indices_to_block]).set_stroke(width = 0)
return lines