|
| 1 | +""" pyplots.ai |
| 2 | +phase-diagram: Phase Diagram (State Space Plot) |
| 3 | +Library: matplotlib 3.10.8 | Python 3.13.11 |
| 4 | +Quality: 93/100 | Created: 2025-12-31 |
| 5 | +""" |
| 6 | + |
| 7 | +import matplotlib.pyplot as plt |
| 8 | +import numpy as np |
| 9 | + |
| 10 | + |
| 11 | +# Damped harmonic oscillator: m*x'' + c*x' + k*x = 0 |
| 12 | +# Using underdamped solution: x(t) = A*exp(-gamma*t)*cos(omega_d*t + phi) |
| 13 | +gamma = 0.15 # Damping coefficient |
| 14 | +omega0 = 1.0 # Natural frequency |
| 15 | +omega_d = np.sqrt(omega0**2 - gamma**2) # Damped frequency (underdamped case) |
| 16 | + |
| 17 | +# Time array |
| 18 | +t = np.linspace(0, 50, 2000) |
| 19 | + |
| 20 | +# Multiple trajectories from different initial conditions |
| 21 | +# Format: (A, phi) - amplitude and phase for analytical solution |
| 22 | +initial_params = [ |
| 23 | + (3.0, 0.0), # Starting from rest, displaced right |
| 24 | + (3.0, 0.5), # Different phase |
| 25 | + (2.5, 2.5), # Another trajectory |
| 26 | + (2.0, 4.0), # Fourth trajectory |
| 27 | +] |
| 28 | + |
| 29 | +# Compute trajectories using analytical solution |
| 30 | +# x(t) = A * exp(-gamma*t) * cos(omega_d*t + phi) |
| 31 | +# v(t) = dx/dt = A * exp(-gamma*t) * (-gamma*cos(omega_d*t + phi) - omega_d*sin(omega_d*t + phi)) |
| 32 | +trajectories = [] |
| 33 | +for A, phi in initial_params: |
| 34 | + exp_decay = A * np.exp(-gamma * t) |
| 35 | + x = exp_decay * np.cos(omega_d * t + phi) |
| 36 | + v = exp_decay * (-gamma * np.cos(omega_d * t + phi) - omega_d * np.sin(omega_d * t + phi)) |
| 37 | + trajectories.append((x, v, A, phi)) |
| 38 | + |
| 39 | +# Colors for trajectories (Python Blue first, then accessible palette) |
| 40 | +colors = ["#306998", "#FFD43B", "#E55934", "#43AA8B"] |
| 41 | + |
| 42 | +# Create figure |
| 43 | +fig, ax = plt.subplots(figsize=(16, 9)) |
| 44 | + |
| 45 | +# Plot each trajectory |
| 46 | +for i, (x, v, A, _phi) in enumerate(trajectories): |
| 47 | + # Plot trajectory line |
| 48 | + ax.plot(x, v, color=colors[i], linewidth=2.5, alpha=0.8, label=f"Trajectory {i + 1} (A={A:.1f})") |
| 49 | + |
| 50 | + # Mark start point with larger marker |
| 51 | + ax.scatter(x[0], v[0], s=250, color=colors[i], edgecolor="white", linewidth=2, zorder=5, marker="o") |
| 52 | + |
| 53 | + # Add arrows to show direction along trajectory |
| 54 | + n_points = len(x) |
| 55 | + n_arrows = 4 |
| 56 | + arrow_indices = np.linspace(100, n_points - 200, n_arrows, dtype=int) |
| 57 | + for idx in arrow_indices: |
| 58 | + dx = x[idx + 10] - x[idx] |
| 59 | + dv = v[idx + 10] - v[idx] |
| 60 | + length = np.sqrt(dx**2 + dv**2) |
| 61 | + if length > 0.01: |
| 62 | + ax.annotate( |
| 63 | + "", |
| 64 | + xy=(x[idx + 10], v[idx + 10]), |
| 65 | + xytext=(x[idx], v[idx]), |
| 66 | + arrowprops={"arrowstyle": "->", "color": colors[i], "lw": 2.5, "mutation_scale": 20}, |
| 67 | + ) |
| 68 | + |
| 69 | +# Mark the equilibrium point (stable fixed point at origin) |
| 70 | +ax.scatter(0, 0, s=400, color="black", marker="x", linewidth=4, zorder=10, label="Equilibrium (stable)") |
| 71 | + |
| 72 | +# Add reference lines for axes |
| 73 | +ax.axhline(y=0, color="gray", linewidth=1.5, linestyle="--", alpha=0.5) |
| 74 | +ax.axvline(x=0, color="gray", linewidth=1.5, linestyle="--", alpha=0.5) |
| 75 | + |
| 76 | +# Labels and styling |
| 77 | +ax.set_xlabel("Position x", fontsize=20) |
| 78 | +ax.set_ylabel("Velocity dx/dt", fontsize=20) |
| 79 | +ax.set_title("Damped Oscillator · phase-diagram · matplotlib · pyplots.ai", fontsize=24) |
| 80 | +ax.tick_params(axis="both", labelsize=16) |
| 81 | +ax.legend(fontsize=14, loc="upper right", framealpha=0.9) |
| 82 | +ax.grid(True, alpha=0.3, linestyle="--") |
| 83 | + |
| 84 | +# Set equal aspect ratio for proper visualization |
| 85 | +ax.set_aspect("equal", adjustable="box") |
| 86 | + |
| 87 | +# Adjust axis limits for better visualization |
| 88 | +ax.set_xlim(-4, 4) |
| 89 | +ax.set_ylim(-3.5, 3.5) |
| 90 | + |
| 91 | +plt.tight_layout() |
| 92 | +plt.savefig("plot.png", dpi=300, bbox_inches="tight") |
0 commit comments