-
Notifications
You must be signed in to change notification settings - Fork 2
/
wave1d.py
141 lines (94 loc) · 2.93 KB
/
wave1d.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""
This is a 1D wave simulation test for education, it is by no means
optimized, and I don't fully guarantee its correctness.
Repo:
https://github.com/bean-mhm/wave-simulation-py
"""
import math
import numpy as np
import matplotlib.pyplot as plt
import time
# Number of points on the string
n = 30
# Distance between each point
dx = 0.5
# Propagation speed
c = 10
# Initial values / vertical positions of the points
pos = [0.0] * n
# Previous values / positions
pos_last = pos.copy()
# Maximum timestep
# dt <= (dx / c)
max_dt = dx / c
# Timestep
dt = 0.5 * max_dt
# Stiffness
# Must be greater than or equal to 1 to function properly.
# The formula is made up and likely not physically correct.
stiffness = 10.0
# Time elapsed in the simulation world
total_time = 0
# Get bound value from an array, returns the default value for
# out-of-bound indices.
def get_bound(arr, index: int, default=0.0):
if (index < 0 or index >= len(arr)):
return default
return arr[index]
# Advance the simulation by dt
def increment():
global pos
global pos_last
global total_time
# Make a backup of the current positions
temp = pos.copy()
# Create an array to store the velocities
vel = [0.0] * n
# We could alternate between two buffers instead of copying
# and allocating new arrays every iteration, but I'm not
# focusing on performance here.
# You can also precalculate constant coefficients outside the loop.
# Go through the points
for i in range(n):
# Calculate the second derivative with respect to x
grad = ((get_bound(pos, i + 1) - get_bound(pos, i)) -
(get_bound(pos, i) - get_bound(pos, i - 1))) / (dx**2)
# Calculate how much we need to adjust the velocity
acc = c**2 * grad
# Get the current velocity
vel[i] = (pos[i] - pos_last[i]) / (dt)
# Adjust the velocity
vel[i] += acc * dt
# "Stiffen"
vel[i] /= stiffness**dt
# Go through the points and adjust the positions based on the
# velocities that we calculated before
for i in range(n):
pos[i] += vel[i] * dt
# Use the backup we made before
pos_last = temp
total_time += dt
# Oscillate a specific point
osc_time = 3.0
if (total_time < osc_time):
strength = 1.0 - (total_time / osc_time)
amp = 0.3 * strength
freq = 40 * strength
pos[10] = math.sin(total_time * freq) * amp
# Make an interactive plot
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_ylim([-1.0, 1.0])
line1, = ax.plot(pos, '-o')
# Update the plot
stepsPerSecond = 30.0
secondsPerStep = 1.0 / stepsPerSecond
last = time.time()
while 1:
if time.time() - last >= secondsPerStep:
last = time.time()
increment()
line1.set_ydata(pos)
fig.canvas.draw()
fig.canvas.flush_events()