Diese Seite bezieht sich auf die erste Auflage (2020) des Buches.   ➜   Zur aktuellen Auflage.

Aufgaben

Lösung zu Aufgabe 4.4

Link    Zur fertigen Animation.

Download    Kinematik/Loesungen/drift_boot.py

"""Simulation und animierte Darstellung eines Bootes, das in
einer Strömung ein Ziel ansteuert. """

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.animation

# Startposition (x, y) des Bootes [m].
r0 = np.array([-10, 2.0])

# Position (x, y) des Zieles [m].
r_ziel = np.array([0.0, 0.0])

# Vektor der Geschwindigkeit (vx, vy) der Strömung [m/s].
v_stroem = np.array([0.0, -2.5])

# Betrag der Relativgeschwindigkeit des Bootes zum Wasser [m/s].
v0_boot = 3.0

# Maximale Simulationsdauer [s].
t_max = 500

# Zeitschrittweite [s].
dt = 0.01

# Brich die Simulation ab, wenn der Abstand von Boot und
# Ziel kleiner als epsilon ist.
epsilon = v0_boot * dt

# Legen Listen an, um die Simulationsergebnisse zu speichern.
t = [0]
r = [r0]     # Ortsvektor des Bootes.
v = []       # Geschwindigkeitsvektor des Bootes.
d = []       # Richtungsvektor (Einheitsvektor) der Bootsspitze.

# Schleife der Simulation.
while True:
    # Lege die Richtung fest, in die das Boot steuert.
    delta_r = r_ziel - r[-1]
    dir_boot = delta_r / np.linalg.norm(delta_r)
    d.append(dir_boot)

    # Berechne den neuen Geschwindigkeitsvektor des Bootes.
    v.append(v0_boot * dir_boot + v_stroem)

    # Beende die Simulation, wenn der Abstand von Boot und
    # Ziel klein genug ist oder die maximale Simulationszeit
    # überschritten ist.
    if (np.linalg.norm(delta_r) < epsilon) or (t[-1] > t_max):
        break

    # Berechne die neue Position des Bootes und die neue Zeit.
    r.append(r[-1] + dt * v[-1])
    t.append(t[-1] + dt)

# Wandele die Listen in Arrays um. Die Zeilen entsprechen den
# Zeitpunkten und die Spalten entsprechen den Koordinaten.
t = np.array(t)
r = np.array(r)
v = np.array(v)
d = np.array(d)

# Erzeuge eine Figure und ein Axes-Objekt.
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('x [m]')
ax.set_ylabel('y [m]')
ax.set_xlim(-11, 1)
ax.set_ylim(-5, 3)
ax.set_aspect('equal')
ax.grid()

# Erzeuge einen leeren Plot für die Bahnkurve des Bootes
plot, = ax.plot([], [])

# Erzeuge zwei Punktplots, mit jeweils nur einem Punkt.
boot, = ax.plot([0], [0], 'o', color='blue')
ziel, = ax.plot(r_ziel[0], r_ziel[1], 'o', color='red')

# Erzeuge zwei Pfeile für die Geschwindigkeit und die aktuelle
# Ausrichtung des Bootes
style = mpl.patches.ArrowStyle.Simple(head_length=6, head_width=3)
arrow_v = mpl.patches.FancyArrowPatch((0, 0), (0, 0),
                                      color='red',
                                      arrowstyle=style)
arrow_d = mpl.patches.FancyArrowPatch((0, 0), (0, 0),
                                      color='black',
                                      arrowstyle=style)

# Füge die Grafikobjekte zur Axes hinzu.
ax.add_artist(arrow_v)
ax.add_artist(arrow_d)


def update(n):
    # Lege den Anfangs- und den Zielpunkt des
    # Geschwindigkeitspfeiles fest.
    arrow_v.set_positions(r[n], r[n] + v[n])

    # Lege den Anfangs und den Zielpunkt des
    # Pfeiles für die Bootsausrichtung fest.
    arrow_d.set_positions(r[n], r[n] + d[n])

    # Aktualisiere die Position des Bootes.
    boot.set_data(r[n].reshape(-1, 1))

    # Plotte die Bahnkurve des Bootes bis zum aktuellen
    # Zeitpunkt.
    plot.set_data(r[:n+1, 0], r[:n+1, 1])

    return boot, arrow_v, arrow_d, plot


# Erzeuge das Animationsobjekt und starte die Animation.
ani = mpl.animation.FuncAnimation(fig, update, interval=30,
                                  frames=t.size, blit=True)
plt.show()