Änderungen von Dokument Animation Reaktionsgeschwindigkeit
Zuletzt geändert von Holger Engels am 2026/10/26 19:37
Von Version 1.1
bearbeitet von Holger Engels
am 2026/10/10 21:25
am 2026/10/10 21:25
Änderungskommentar:
Es gibt keinen Kommentar für diese Version
Auf Version 3.1
bearbeitet von Holger Engels
am 2026/10/10 21:25
am 2026/10/10 21:25
Änderungskommentar:
Neuen Anhang reaktionskinetik.json hochladen
Zusammenfassung
-
Anhänge (0 geändert, 2 hinzugefügt, 0 gelöscht)
Details
- reaktionskinetik.json
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +xwiki:XWiki.holgerengels - Größe
-
... ... @@ -1,0 +1,1 @@ 1 +2.3 KB - Inhalt
-
... ... @@ -1,0 +1,48 @@ 1 +{ 2 + "id": "reaktionskinetik", 3 + "title": "Reaktionskinetik", 4 + "subtitle": "Ermittlung der Reaktionsgeschwindigkeit", 5 + "pageTitle": "Präsentation: Grafische Ermittlung der Reaktionsgeschwindigkeit", 6 + "recordFilename": "Erklaervideo_Reaktionskinetik", 7 + "finishLabel": "Mittlere vs. momentane Reaktionsgeschwindigkeit", 8 + "video": "ReaktionskinetikAnimation.mp4", 9 + "sections": [ 10 + { 11 + "id": "01_Initialisierung", 12 + "title": "1. Initialisierung: Aufbau & Diagramm", 13 + "desc": "Erlenmeyerkolben mit Eduktlösung (c₀ = 1,0 mol/l) links und Koordinatensystem (Konzentration c gegen Zeit t) rechts mit Formel v = |Δc|/Δt.", 14 + "duration": 2.400000 15 + }, 16 + { 17 + "id": "02_Reaktion_und_Messpunkte", 18 + "title": "2. Reaktion, Messpunkte & Näherungskurve", 19 + "desc": "Reaktion läuft ab: Eduktlösung entfärbt sich im Erlenmeyerkolben; Messpunkte erscheinen mit gleichmäßigem Zeitabstand (Δt = 250 s) voll synchron. Am Ende bildet sich die glatte Ausgleichskurve c(t).", 20 + "duration": 5.600000 21 + }, 22 + { 23 + "id": "03_Zoom_und_Ausgleichskurve", 24 + "title": "3. Zoom ins Diagramm (Punkte ausgeblendet)", 25 + "desc": "Erlenmeyerkolben und diskrete Messpunkte werden ausgeblendet; das Diagramm mit der bereinigten Ausgleichskurve wird zentriert vergrößert.", 26 + "duration": 2.400000 27 + }, 28 + { 29 + "id": "04_Mittlere_Aenderungsrate", 30 + "title": "4. Mittlere Änderungsrate (Sekante)", 31 + "desc": "Sekantensteigung im Intervall [1000 s, 2000 s] (blau); Steigungsdreieck oberhalb der Kurve mit einheitlicher Breite Δt = 1000 s liefert v̄ ≈ 2,5·10⁻⁴ mol/(l·s).", 32 + "duration": 6.400000 33 + }, 34 + { 35 + "id": "05_Momentane_Aenderungsrate", 36 + "title": "5. Momentane Änderungsrate (Tangente)", 37 + "desc": "Tangentensteigung im Kurvenpunkt bei t = 3000 s (rot); Steigungsdreieck oberhalb mit einheitlicher Breite Δt = 1000 s liefert v(3000 s) ≈ 7,5·10⁻⁵ mol/(l·s).", 38 + "duration": 6.400000 39 + }, 40 + { 41 + "id": "06_Startgeschwindigkeit", 42 + "title": "6. Startgeschwindigkeit (Tangente bei t = 0)", 43 + "desc": "Tangentensteigung zum Startzeitpunkt t = 0 s (grün) mit Steigungsdreieck oberhalb (Δt = 1000 s, Δc = 0,78 mol/l); liefert v₀ ≈ 7,8·10⁻⁴ mol/(l·s). Alle drei Methoden sind nebeneinander dargestellt.", 44 + "duration": 4.300000 45 + } 46 + ] 47 +} 48 +
- reaktionskinetik.py
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +xwiki:XWiki.holgerengels - Größe
-
... ... @@ -1,0 +1,1 @@ 1 +17.9 KB - Inhalt
-
... ... @@ -1,0 +1,438 @@ 1 +from manim import * 2 +import numpy as np 3 +from styles import * 4 + 5 +# ============================================================================= 6 +# 1. MATHEMATISCHES & CHEMISCHES MODELL 7 +# ============================================================================= 8 +# Eduktkonzentration: c(t) = c_0 * exp(-k * t) 9 +# c_0 = 1.0 mol/l 10 +# k = 0.00078 s^-1 11 +# t in [0, 4000] Sekunden 12 + 13 +C_0 = 1.0 14 +K_RATE = 0.00078 15 + 16 +def get_conc(t): 17 + """Konzentration des Edukts zum Zeitpunkt t in mol/l.""" 18 + return C_0 * np.exp(-K_RATE * t) 19 + 20 +def get_reaction_rate(t): 21 + """Betrag der momentanen Reaktionsgeschwindigkeit v(t) = |dc/dt| in mol/(l*s).""" 22 + return K_RATE * C_0 * np.exp(-K_RATE * t) 23 + 24 +def get_solution_color(c_val): 25 + """ 26 + Farbverlauf der Reaktionslösung im Erlenmeyerkolben: 27 + Tiefes Kristallviolett bei c=1.0 mol/l 28 + -> Hellviolett / Rosa bei c=0.5 mol/l 29 + -> Fast farblos / transparent-wässrig bei c->0. 30 + """ 31 + alpha = float(np.clip(c_val / 1.0, 0.0, 1.0)) 32 + c_start = ManimColor("#6A1B9A") # Tiefes Violett 33 + c_mid = ManimColor("#BA68C8") # Helles Rosa-Violett 34 + c_end = ManimColor("#E1BEE7") # Blasses, wässriges Violett 35 + 36 + if alpha > 0.4: 37 + return interpolate_color(c_mid, c_start, (alpha - 0.4) / 0.6) 38 + else: 39 + return interpolate_color(c_end, c_mid, alpha / 0.4) 40 + 41 +def get_solution_opacity(c_val): 42 + alpha = float(np.clip(c_val / 1.0, 0.0, 1.0)) 43 + return 0.20 + 0.70 * alpha 44 + 45 +# Farbcodierung analog zum Arbeitsblatt 46 +COLOR_DURCHSCHNITT = COLOR_INFLOW # #00E5FF (Cyan / Blau für Sekante / mittlere Änderungsrate) 47 +COLOR_MOMENTAN = COLOR_OUTFLOW # #FF5252 (Korallrot für Tangente / momentane Änderungsrate) 48 +COLOR_ANFANG = COLOR_EQUILIBRIUM # #26A69A (Grün für Anfangsgeschwindigkeit) 49 + 50 + 51 +def create_erlenmeyer(width=2.4, height=3.0): 52 + """ 53 + Erstellt einen detailreichen Erlenmeyerkolben mit Glaswand, 54 + Skalenstrichen und dynamischer Flüssigkeitsfüllung. 55 + """ 56 + neck_w = 0.60 57 + neck_h = 0.90 58 + base_w = width 59 + body_h = height - neck_h 60 + rim_w = 0.76 61 + rim_h = 0.10 62 + 63 + # Eckpunkte des Glaskörpers (konischer Rumpf) 64 + p_bl = np.array([-base_w/2, -body_h/2, 0]) 65 + p_br = np.array([ base_w/2, -body_h/2, 0]) 66 + p_tr = np.array([ neck_w/2, body_h/2, 0]) 67 + p_tl = np.array([-neck_w/2, body_h/2, 0]) 68 + 69 + body = Polygon( 70 + p_bl, p_br, p_tr, p_tl, 71 + stroke_color=WHITE, stroke_width=2.4, 72 + fill_color="#101422", fill_opacity=0.4 73 + ) 74 + 75 + neck = Rectangle( 76 + width=neck_w, height=neck_h, 77 + stroke_color=WHITE, stroke_width=2.4, 78 + fill_color="#101422", fill_opacity=0.4 79 + ).next_to(body, UP, buff=0) 80 + 81 + rim = RoundedRectangle( 82 + corner_radius=0.04, width=rim_w, height=rim_h, 83 + stroke_color=WHITE, stroke_width=1.8, 84 + fill_color="#1E2438", fill_opacity=0.9 85 + ).next_to(neck, UP, buff=0) 86 + 87 + # Skalenstriche auf dem Glas 88 + marks = VGroup() 89 + for dy in [-0.5, -0.15, 0.2]: 90 + m_line = Line([-neck_w*0.8, dy, 0], [-neck_w*0.4, dy, 0], stroke_color=GREY_A, stroke_width=1.4) 91 + marks.add(m_line) 92 + 93 + glass = VGroup(body, neck, rim, marks) 94 + 95 + # Flüssigkeits-Trapez (Füllstand ca. 72% der Rumpfhöhe) 96 + fill_ratio = 0.72 97 + y_liquid_top = -body_h/2 + body_h * fill_ratio 98 + top_w = base_w - (base_w - neck_w) * fill_ratio 99 + 100 + l_bl = np.array([-base_w/2 + 0.05, -body_h/2 + 0.05, 0]) 101 + l_br = np.array([ base_w/2 - 0.05, -body_h/2 + 0.05, 0]) 102 + l_tr = np.array([ top_w/2 - 0.03, y_liquid_top, 0]) 103 + l_tl = np.array([-top_w/2 + 0.03, y_liquid_top, 0]) 104 + 105 + liquid = Polygon( 106 + l_bl, l_br, l_tr, l_tl, 107 + stroke_width=0, fill_color=ManimColor("#6A1B9A"), fill_opacity=0.85 108 + ) 109 + 110 + meniscus = Line(l_tl, l_tr, stroke_color="#CE93D8", stroke_width=2.0) 111 + 112 + return VGroup(liquid, meniscus, glass), liquid, meniscus 113 + 114 + 115 +class ReaktionskinetikAnimation(Scene): 116 + def construct(self): 117 + self.camera.background_color = COLOR_BG 118 + 119 + # ------------------------------------------------------------- 120 + # 1. Schritt: Initialisierung 121 + # ------------------------------------------------------------- 122 + self.next_section("01_Initialisierung") 123 + 124 + formula_header = MathTex( 125 + r"\text{Reaktionsgeschwindigkeit: } v = \frac{|\Delta c|}{\Delta t}", 126 + font_size=FONT_SIZE_FORMULA, color=COLOR_STEP_LINE 127 + ).to_edge(UP, buff=0.15) 128 + 129 + self.play(Write(formula_header), run_time=0.8) 130 + 131 + # Erlenmeyerkolben links 132 + flask_group, liquid_poly, meniscus_line = create_erlenmeyer(width=2.4, height=3.0) 133 + flask_group.move_to([-4.6, -0.3, 0]) 134 + 135 + flask_title = Tex(r"\textbf{Reaktionsansatz}", font_size=16, color=WHITE).next_to(flask_group, UP, buff=0.18) 136 + c_label = Tex(r"$c(\text{Edukt}) = $", font_size=15, color=COLOR_TEXT_MUTED) 137 + c_num = DecimalNumber(1.0, num_decimal_places=2, unit=r"\,\text{mol/l}", font_size=15, color=WHITE) 138 + c_readout = VGroup(c_label, c_num).arrange(RIGHT, buff=0.06).next_to(flask_group, DOWN, buff=0.22) 139 + 140 + erlenmeyer_full = VGroup(flask_group, flask_title, c_readout) 141 + 142 + # Koordinatensystem rechts 143 + axes = Axes( 144 + x_range=[0, 4200, 500], 145 + y_range=[0, 1.25, 0.2], 146 + x_length=6.4, 147 + y_length=4.4, 148 + axis_config=AXIS_COMMON_CONFIG, 149 + x_axis_config=get_x_axis_config([500, 1000, 1500, 2000, 2500, 3000, 3500, 4000], font_size=14), 150 + y_axis_config=get_y_axis_config([0.2, 0.4, 0.6, 0.8, 1.0, 1.2], font_size=14) 151 + ).move_to([1.8, -0.35, 0]) 152 + 153 + y_label = Tex(r"Konzentration $c$ [$\text{mol}\cdot\text{l}^{-1}$]", font_size=15, color=COLOR_TEXT_PRIMARY).next_to( 154 + axes.y_axis.get_top(), UP, buff=0.10 155 + ).shift(RIGHT * 1.0) 156 + x_label = Tex(r"Zeit $t$ [$\text{s}$]", font_size=16, color=COLOR_TEXT_MUTED).next_to( 157 + axes.x_axis.get_end(), RIGHT, buff=0.15 158 + ) 159 + 160 + axes_group = VGroup(axes, x_label, y_label) 161 + 162 + self.play( 163 + FadeIn(erlenmeyer_full), 164 + Create(axes), Write(x_label), Write(y_label), 165 + run_time=1.2 166 + ) 167 + self.wait(0.4) 168 + 169 + # ------------------------------------------------------------- 170 + # 2. Schritt: Reaktion und Punkte .. am Ende erscheint die Näherungskurve 171 + # ------------------------------------------------------------- 172 + self.next_section("02_Reaktion_und_Messpunkte") 173 + 174 + np.random.seed(42) 175 + sample_times = np.arange(0, 4001, 250) 176 + noisy_concs = np.clip(get_conc(sample_times) + np.random.normal(0, 0.018, len(sample_times)), 0.02, 1.05) 177 + noisy_concs[0] = 1.00 178 + 179 + t_tracker = ValueTracker(0.0) 180 + 181 + # Updater für Flüssigkeitsfarbe & Konzentration 182 + liquid_poly.add_updater(lambda m: m.set_color(get_solution_color(get_conc(t_tracker.get_value()))).set_opacity(get_solution_opacity(get_conc(t_tracker.get_value())))) 183 + c_num.add_updater(lambda m: m.set_value(get_conc(t_tracker.get_value()))) 184 + 185 + # Punktwolke der Messwerte mit Rauschen 186 + noisy_dots = VGroup() 187 + for t_s, c_s in zip(sample_times, noisy_concs): 188 + dot = Dot(axes.c2p(t_s, c_s), radius=0.065, color="#81D4FA") 189 + dot.set_opacity(0.0) 190 + noisy_dots.add(dot) 191 + 192 + # Updater für synchrone Messpunkterfassung exakt zum jeweiligen Reaktionszeitpunkt t_s 193 + def update_noisy_dots(group): 194 + curr_t = t_tracker.get_value() 195 + for dot, t_s in zip(group, sample_times): 196 + if curr_t < t_s: 197 + dot.set_opacity(0.0) 198 + else: 199 + dt = curr_t - t_s 200 + flash_window = 140.0 201 + if dt < flash_window: 202 + frac = dt / flash_window 203 + dot.set_opacity(1.0) 204 + dot.set_color(interpolate_color(WHITE, ManimColor("#81D4FA"), frac)) 205 + else: 206 + dot.set_opacity(1.0) 207 + dot.set_color(ManimColor("#81D4FA")) 208 + 209 + noisy_dots.add_updater(update_noisy_dots) 210 + self.add(noisy_dots) 211 + 212 + # Reaktion läuft ab: Entfärbung der Flüssigkeit und Erscheinen der Punkte erfolgen synchron (erhöhte Geschwindigkeit) 213 + self.play( 214 + t_tracker.animate.set_value(4000.0), 215 + run_time=3.2, 216 + rate_func=linear 217 + ) 218 + self.wait(0.3) 219 + noisy_dots.clear_updaters() 220 + for dot in noisy_dots: 221 + dot.set_opacity(1.0) 222 + dot.set_color(ManimColor("#81D4FA")) 223 + 224 + # Am Ende dieses Schritts: Näherungskurve erscheint durch die Punkte! 225 + full_curve = axes.plot(lambda t: get_conc(t), x_range=[0, 4000], color=COLOR_STEP_LINE, stroke_width=3.4) 226 + curve_label = Tex(r"\textbf{Ausgleichskurve} $c(t)$", font_size=14, color=COLOR_STEP_LINE).next_to( 227 + axes.c2p(500, get_conc(500)), UR, buff=0.10 228 + ) 229 + 230 + self.play(Create(full_curve), FadeIn(curve_label), run_time=1.5) 231 + self.wait(0.6) 232 + 233 + # ------------------------------------------------------------- 234 + # 3. Schritt: Zoom und Punkte verschwinden 235 + # ------------------------------------------------------------- 236 + self.next_section("03_Zoom_und_Ausgleichskurve") 237 + 238 + liquid_poly.clear_updaters() 239 + c_num.clear_updaters() 240 + 241 + diagram_all = VGroup(axes, x_label, y_label, full_curve) 242 + target_center = np.array([-2.45, -0.30, 0.0]) 243 + zoom_scale = 1.12 244 + 245 + self.play( 246 + FadeOut(erlenmeyer_full, shift=LEFT * 1.5), 247 + FadeOut(noisy_dots, scale=0.8), 248 + FadeOut(curve_label), 249 + diagram_all.animate.move_to(target_center).scale(zoom_scale), 250 + run_time=1.8 251 + ) 252 + self.wait(0.6) 253 + 254 + # ------------------------------------------------------------- 255 + # 4. Schritt: Mittlere Änderungsrate (Sekante 1000 - 2000 s) 256 + # ------------------------------------------------------------- 257 + self.next_section("04_Mittlere_Aenderungsrate") 258 + 259 + t1, t2 = 1000.0, 2000.0 260 + c1, c2 = get_conc(t1), get_conc(t2) 261 + pt1 = axes.c2p(t1, c1) 262 + pt2 = axes.c2p(t2, c2) 263 + 264 + # 1. Zeitpunkte auf der x-Achse & von unten nach oben animierte Projektionslinien 265 + p_axis_1 = axes.c2p(t1, 0) 266 + p_axis_2 = axes.c2p(t2, 0) 267 + 268 + dot_axis1 = Dot(p_axis_1, radius=0.05, color=COLOR_DURCHSCHNITT) 269 + dot_axis2 = Dot(p_axis_2, radius=0.05, color=COLOR_DURCHSCHNITT) 270 + proj_line_1 = DashedLine(p_axis_1, pt1, color=COLOR_DURCHSCHNITT, stroke_width=2.0, dash_length=0.07) 271 + proj_line_2 = DashedLine(p_axis_2, pt2, color=COLOR_DURCHSCHNITT, stroke_width=2.0, dash_length=0.07) 272 + 273 + self.play(FadeIn(dot_axis1), FadeIn(dot_axis2), run_time=0.3) 274 + self.play( 275 + Create(proj_line_1), Create(proj_line_2), 276 + run_time=1.0 277 + ) 278 + self.wait(0.2) 279 + 280 + # 2. Punkte auf der Kurve erscheinen 281 + dot1 = create_data_point(pt1, is_milestone=True, color=COLOR_DURCHSCHNITT) 282 + dot2 = create_data_point(pt2, is_milestone=True, color=COLOR_DURCHSCHNITT) 283 + 284 + self.play( 285 + FadeIn(dot1, scale=1.5), 286 + FadeIn(dot2, scale=1.5), 287 + run_time=0.6 288 + ) 289 + self.wait(0.2) 290 + 291 + # 3. Delta y (|Delta c|) und Delta x (Delta t) - FONT_SIZE_DELTA aus styles.py für optimale Lesbarkeit 292 + pt_corner = axes.c2p(t2, c1) 293 + tri_sec_dc = Line(pt_corner, pt2, color=COLOR_DURCHSCHNITT, stroke_width=2.2) 294 + dc_sec_lbl = MathTex(r"|\Delta c| \approx 0{,}25\,\frac{\text{mol}}{\text{l}}", font_size=FONT_SIZE_DELTA, color=COLOR_DURCHSCHNITT).next_to(tri_sec_dc, RIGHT, buff=0.10) 295 + 296 + tri_sec_dt = Line(pt1, pt_corner, color=COLOR_DURCHSCHNITT, stroke_width=2.2) 297 + dt_sec_lbl = MathTex(r"\Delta t = 1000\,\text{s}", font_size=FONT_SIZE_DELTA, color=COLOR_DURCHSCHNITT).next_to(tri_sec_dt, UP, buff=0.10) 298 + 299 + self.play(Create(tri_sec_dc), Write(dc_sec_lbl), run_time=0.7) 300 + self.play(Create(tri_sec_dt), Write(dt_sec_lbl), run_time=0.7) 301 + self.wait(0.2) 302 + 303 + # 4. Sekante und Info-Badge (am rechten Rand) 304 + sec_dir = normalize(pt2 - pt1) 305 + sec_start = pt1 - sec_dir * 0.7 306 + sec_end = pt2 + sec_dir * 0.7 307 + secant_line = Line(sec_start, sec_end, color=COLOR_DURCHSCHNITT, stroke_width=3.2) 308 + 309 + badge_sec = create_info_badge( 310 + r"\textbf{Sekante} $\mathbf{\hat{=}}$ \textbf{Mittlere Rate}", 311 + r"$\bar{v} = \frac{|\Delta c|}{\Delta t} \approx 2{,}5 \times 10^{-4}\,\frac{\text{mol}}{\text{l}\cdot\text{s}}$", 312 + border_color=COLOR_DURCHSCHNITT, width=4.7, height=1.18, 313 + font_size_title=22, font_size_body=21 314 + ).move_to([4.45, 1.70, 0]) 315 + 316 + self.play( 317 + Create(secant_line), 318 + FadeIn(badge_sec, shift=LEFT * 0.2), 319 + proj_line_1.animate.set_stroke(opacity=0.35), 320 + proj_line_2.animate.set_stroke(opacity=0.35), 321 + run_time=1.0 322 + ) 323 + self.wait(1.5) 324 + 325 + # ------------------------------------------------------------- 326 + # 5. Schritt: Momentane Änderungsrate (Tangente t = 3000 s, nebeneinander zur Sekante) 327 + # ------------------------------------------------------------- 328 + self.next_section("05_Momentane_Aenderungsrate") 329 + 330 + tm = 3000.0 331 + cm = get_conc(tm) 332 + pt_m = axes.c2p(tm, cm) 333 + 334 + # 1. Erst der senkrechte Strich (von der Zeitachse nach oben zur Kurve) 335 + p_axis_m = axes.c2p(tm, 0) 336 + dot_axis_m = Dot(p_axis_m, radius=0.05, color=COLOR_MOMENTAN) 337 + proj_line_m = DashedLine(p_axis_m, pt_m, color=COLOR_MOMENTAN, stroke_width=2.0, dash_length=0.07) 338 + 339 + self.play(FadeIn(dot_axis_m), run_time=0.3) 340 + self.play(Create(proj_line_m), run_time=0.9) 341 + self.wait(0.2) 342 + 343 + # 2. Dann der Punkt auf der Kurve 344 + dot_m = create_data_point(pt_m, is_milestone=True, color=COLOR_MOMENTAN) 345 + self.play(FadeIn(dot_m, scale=1.5), run_time=0.5) 346 + self.wait(0.2) 347 + 348 + # 3. Schließlich die Tangente mit einem Steigungsdreieck (oberhalb, Breite 1000 s) 349 + t_tan_start, t_tan_end = 2400.0, 3600.0 350 + slope_m = -K_RATE * cm 351 + c_tan_start = cm + slope_m * (t_tan_start - tm) 352 + c_tan_end = cm + slope_m * (t_tan_end - tm) 353 + 354 + pt_tan_s = axes.c2p(t_tan_start, c_tan_start) 355 + pt_tan_e = axes.c2p(t_tan_end, c_tan_end) 356 + tan_m_line = Line(pt_tan_s, pt_tan_e, color=COLOR_MOMENTAN, stroke_width=3.2) 357 + 358 + # Steigungsdreieck an der Tangente (oberhalb der Tangente von 2500 bis 3500 s, Breite 1000) 359 + t_tri1 = 2500.0 360 + t_tri2 = 3500.0 361 + c_tri1 = cm + slope_m * (t_tri1 - tm) 362 + c_tri2 = cm + slope_m * (t_tri2 - tm) 363 + 364 + p_tri_start = axes.c2p(t_tri1, c_tri1) 365 + p_tri_corner = axes.c2p(t_tri2, c_tri1) 366 + p_tri_end = axes.c2p(t_tri2, c_tri2) 367 + 368 + tri_tan_dt = Line(p_tri_start, p_tri_corner, color=COLOR_MOMENTAN, stroke_width=2.2) 369 + tri_tan_dc = Line(p_tri_corner, p_tri_end, color=COLOR_MOMENTAN, stroke_width=2.2) 370 + 371 + dt_tan_lbl = MathTex(r"\Delta t = 1000\,\text{s}", font_size=FONT_SIZE_DELTA, color=COLOR_MOMENTAN).next_to(tri_tan_dt, UP, buff=0.08) 372 + dc_tan_lbl = MathTex(r"|\Delta c| \approx 0{,}075\,\frac{\text{mol}}{\text{l}}", font_size=FONT_SIZE_DELTA, color=COLOR_MOMENTAN).next_to(tri_tan_dc, RIGHT, buff=0.10) 373 + 374 + # Info-Badge rechts unter dem 1. Badge (ohne v im Titel, vergrößerte Schrift) 375 + badge_tan = create_info_badge( 376 + r"\textbf{Tangente} $\mathbf{\hat{=}}$ \textbf{Momentane Rate}", 377 + r"$v = \frac{|\Delta c|}{\Delta t} \approx 7{,}5 \times 10^{-5}\,\frac{\text{mol}}{\text{l}\cdot\text{s}}$", 378 + border_color=COLOR_MOMENTAN, width=4.7, height=1.18, 379 + font_size_title=22, font_size_body=21 380 + ).move_to([4.45, 0.35, 0]) 381 + 382 + self.play(Create(tan_m_line), run_time=1.0) 383 + self.play( 384 + Create(tri_tan_dt), Write(dt_tan_lbl), 385 + Create(tri_tan_dc), Write(dc_tan_lbl), 386 + run_time=1.0 387 + ) 388 + self.play( 389 + FadeIn(badge_tan, shift=LEFT * 0.2), 390 + proj_line_m.animate.set_stroke(opacity=0.35), 391 + run_time=0.8 392 + ) 393 + self.wait(1.5) 394 + 395 + # ------------------------------------------------------------- 396 + # 6. Schritt: Startgeschwindigkeit (Tangente t = 0 s, oberhalb, Breite 1000 s) 397 + # ------------------------------------------------------------- 398 + self.next_section("06_Startgeschwindigkeit") 399 + 400 + p0 = axes.c2p(0, 1.0) 401 + p0_end = axes.c2p(1282, 0.0) 402 + 403 + tan_0 = Line(p0, p0_end, color=COLOR_ANFANG, stroke_width=3.2) 404 + dot_0 = create_data_point(p0, is_milestone=True, color=COLOR_ANFANG) 405 + 406 + # Steigungsdreieck oberhalb mit Breite 1000 s (von t = 0 bis t = 1000 s) 407 + t0_start = 0.0 408 + t0_end = 1000.0 409 + c0_start = 1.0 410 + c0_end = 1.0 - K_RATE * 1000.0 # 0.22 mol/l 411 + 412 + p_0_start = axes.c2p(t0_start, c0_start) 413 + p_0_corner = axes.c2p(t0_end, c0_start) 414 + p_0_tan_pt = axes.c2p(t0_end, c0_end) 415 + 416 + tri_0_dt = Line(p_0_start, p_0_corner, color=COLOR_ANFANG, stroke_width=2.2) 417 + tri_0_dc = Line(p_0_corner, p_0_tan_pt, color=COLOR_ANFANG, stroke_width=2.2) 418 + 419 + dt_0_lbl = MathTex(r"\Delta t = 1000\,\text{s}", font_size=FONT_SIZE_DELTA, color=COLOR_ANFANG).next_to(tri_0_dt, UP, buff=0.08) 420 + dc_0_lbl = MathTex(r"|\Delta c| = 0{,}78\,\frac{\text{mol}}{\text{l}}", font_size=FONT_SIZE_DELTA, color=COLOR_ANFANG).next_to(tri_0_dc, RIGHT, buff=0.10) 421 + 422 + # Info-Badge rechts unter dem 2. Badge 423 + badge_0 = create_info_badge( 424 + r"\textbf{Tangente} $\mathbf{\hat{=}}$ \textbf{Startgeschwindigkeit}", 425 + r"$v_0 = \frac{|\Delta c|}{\Delta t} \approx 7{,}8 \times 10^{-4}\,\frac{\text{mol}}{\text{l}\cdot\text{s}}$", 426 + border_color=COLOR_ANFANG, width=4.7, height=1.18, 427 + font_size_title=22, font_size_body=21 428 + ).move_to([4.45, -1.00, 0]) 429 + 430 + self.play( 431 + FadeIn(dot_0), Create(tan_0), 432 + Create(tri_0_dt), Write(dt_0_lbl), 433 + Create(tri_0_dc), Write(dc_0_lbl), 434 + FadeIn(badge_0, shift=LEFT * 0.2), 435 + run_time=1.8 436 + ) 437 + self.wait(2.5) 438 +