"""
Waves on a Piano String.
This program solves the wave equation for a 1D piano string.
The string is of length L and initially at rest.
At time t = 0 it is struck with velocity v to have displacement d.
The displacement, "height", at each position for an array of times
is calculated. A plot of the propogating wave is made for each
user input value of alpha.
"""
# Import Packages
import numpy as np
import matplotlib.pyplot as plt
# Calculates the time step for all positions
def timeStep(a,v,alpha):
return (a*np.sqrt(alpha))/v
# Calculates the initial velocity at a position
def velocity(x,C,L,d,s):
return (C/L**2)*x*(L-x)*np.exp( (-(x-d)**2)/(2*s**2))
# Calculates the height for any position at a new time
def anyStep(wave,alpha,x,t):
return 2*(1-alpha)*wave[x,t] + alpha*(wave[x+1,t]+wave[x-1,t]) - wave[x,t-1]
# Initialize constants
v = 100 # velocity of wave on string (m/s)
L = 1 # string length (m)
d = 0.1 # displacement (m)
C = 1 # speed (m/s)
s = 0.03 # st.dev. (m)
a = 0.5/100 # spatial step (m)
N = int(L/a) # Number of positions
# Request values for alpha and save to an array
quan = int(input("How many alphas would you like to try? "))
alphas = np.zeros(quan)
for q in range(quan): alphas[q] = float(input("alpha = "))
# Make a plot for each alpha
for q in range(quan):
# Initialize variables
alpha = alphas[q] # user input value
h = timeStep(a,v,alpha) # time step
n = int(0.1/h) # Number of times
# Arrays
wave = np.zeros([N,n], float) # position,time
positions = np.linspace(0,L,N) # positions on the string
times = np.linspace(0,0.1,n) # range of times
# Calculate the initial velocity at every position
velocities = velocity(positions,C,L,d,s)
# Calculate the heights for the first time step
heights = h*velocities
# Define the heights for the first time step
wave[:,1] = heights
# Calculate heights for each (x,t) condition to fufill the "wave" array
for t in range(1,n-1):
for x in range(1,N-1):
wave[x,t+1] = anyStep(wave,alpha,x,t)
# Create a new figure if necessary
if q > 0:
plt.figure()
# Plot the height vs. position for specified times
for k in range(0,n,100):
plt.plot(positions,wave[:,k])
# Label and show the plot
plt.title("Piano Wave Height vs. Position on Wave\nalpha = " + str(alpha))
plt.show()
When the wave pulse encounters the right boundary, it is reflected over the x axis. As the wave is inverting, its amplitude decreases to zero, then increases in the negative y-direction, restoring the string’s equilibrium displacement, before it travels in the opposite horizontal direction prior to the reflection. When it encounters the left boundary, another reflection occurs, with the magnitude of the amplitude decreasing to zero, then increasing in the positive y-direction.
When the hammer strikes the string, the string has a deformation at that point. The amplitude increases to create a narrow curve, which is two overlapping waves. The waves travel outward from the point of initial deformation. The two travelling waves creates a slowly widening hump. This hump propagates to the right and follows the reflection pattern as described in part 3.
The values of alpha than can be assumed to yield reliable numerical solutions is for alpha < 1. When alpha is greater than 1, the plot is no longer a propagating wave. When the value equals one, the shape of the wave does not have an accurate enough approximation such that its hump is uniform, which does not resemble the physical appearance of a wave on a piano string. The smaller the alpha, the better the approximation because smaller steps are taken when calculating the height of the wave at a position for the next time.
Alpha = 1 behaves as a boundary for stability due to the height equation’s term for dependence on the present position and time having a negative sign. Because of this, the sign of the height is oscillating and increasing at each position, and the height is no longer converting to a fixed value.