Mechanical waves arise as a result of the application of simple harmonic motion rules to interconnected systems. At their core, such waves can be visualized as particles connected by springs, where each particle’s motion influences the next. This elegant interplay between force, displacement, and energy transfer forms the foundation of mechanical wave dynamics.
To illustrate this concept, imagine a chain of small masses connected by springs. When one mass is displaced, the motion propagates through the entire system, creating a wave-like pattern. You can explore this phenomenon in action with a simulation of ten masses linked by springs:
A plane harmonic wave is a fundamental example of wave motion, described by a sinusoidal function such as:
\[
\psi(x, t) = A \sin(kx - \omega t + \phi),
\]
where:
\(A\) is the amplitude,
\(k\) is the wave number,
\(\omega\) is the angular frequency,
\(\phi\) is the phase constant,
\(x\) and \(t\) represent position and time, respectively.
Show the code
import numpy as npimport matplotlib.pyplot as plt# Parameters for the waveA =1.0# Amplitudelambda_wave =4.0# Wavelengthk =2* np.pi / lambda_wave # Wave numberphi =0# Phase constantx = np.linspace(0, 8, 1000) # Range for x# Wave functionpsi = A * np.sin(k * x - phi)# Plot the wave functionplt.figure(figsize=(12, 6))plt.plot(x, psi, label="$\\psi(x) = A \\sin(kx - \\phi)$", color="blue")# Mark the amplitudeplt.plot([lambda_wave /4, lambda_wave /4], [0, A], color="green", linewidth=2)plt.text(lambda_wave /4+0.2, A /2, r'Amplitude $A$', fontsize=12, ha='left', color="green")# Mark the segment from 1 to 5 with vertical lines at the endsx_start =1x_end =5y_label = A +0.3# Position above the wave to mark the segmentplt.plot([x_start, x_end], [y_label, y_label], color="red", linewidth=2) # Horizontal lineplt.plot([x_start, x_start], [y_label -0.05, y_label +0.05], color="red", linewidth=2) # Vertical line at startplt.plot([x_end, x_end], [y_label -0.05, y_label +0.05], color="red", linewidth=2) # Vertical line at endplt.text((x_start + x_end) /2, y_label -0.1, "$\\lambda$", fontsize=12, ha='center', color="red") # Label above the segment# Add auxiliary linesplt.axhline(y=0, color='gray', linestyle='--', linewidth=0.7, alpha=0.5) # Horizontal axisplt.axhline(y=A, color='gray', linestyle='--', linewidth=0.7) # Amplitude lineplt.axhline(y=-A, color='gray', linestyle='--', linewidth=0.7) # Negative amplitude line# Configure axesplt.xlabel("Position $x$", fontsize=14)plt.ylabel("Wave function $\\psi(x)$", fontsize=14)# Add gridplt.grid(True, linestyle="--", alpha=0.7)# Display the plotplt.show()
Constructing the Wave Equation
The temporal and spatial derivatives of the wave function \(\psi(x, t)\) are key to understanding its behavior. The first and second derivatives with respect to time \(t\) are:
\[
\frac{\partial \psi}{\partial t} = -A \omega \cos(kx - \omega t + \phi),
\]
\[
\frac{\partial^2 \psi}{\partial t^2} = -A \omega^2 \sin(kx - \omega t + \phi).
\]
Similarly, the first and second derivatives with respect to position \(x\) are:
\[
\frac{\partial \psi}{\partial x} = A k \cos(kx - \omega t + \phi),
\]
\[
\frac{\partial^2 \psi}{\partial x^2} = -A k^2 \sin(kx - \omega t + \phi).
\]
By combining these derivatives, we can see how the wave function satisfies the general wave equation. Substituting \(\frac{\partial^2 \psi}{\partial x^2}\) and \(\frac{\partial^2 \psi}{\partial t^2}\) into:
and using the relations \(v = \frac{\omega}{k}\), it becomes clear that the sinusoidal wave satisfies this fundamental equation, connecting temporal and spatial changes in the wave function.
General Implications
What we have derived here is not just a coincidence but is, in fact, the result of more general considerations. The equation we obtained, often called the wave equation, emerges from the fundamental principles governing wave phenomena. It describes the behavior of a wide range of wave-like systems, including sound waves, water waves, and even electromagnetic waves in certain contexts. As such, it is recognized as one of the cornerstone equations in the study of physical systems exhibiting wave motion.
Let us begin! First, we will derive the difference equations that allow for the numerical solution of the wave equation. Here is the plan:
Assume that: - We divide the space \(x\) into \(N\) equal intervals of length \(\Delta x\). - We divide the time \(t\) into steps of length \(\Delta t\).
The function \(\psi(x, t)\) is replaced by a discrete grid \(\psi_i^n\), where \(i\) denotes the spatial index and \(n\) denotes the time index:
\(i = 0, 1, 2, \dots, N\),
\(n = 0, 1, 2, \dots\).
Finite Difference Approximations
Second spatial derivatives: Approximate \(\frac{\partial^2 \psi}{\partial x^2}\) using central differences: \[
\frac{\partial^2 \psi}{\partial x^2} \approx \frac{\psi_{i+1}^n - 2\psi_i^n + \psi_{i-1}^n}{\Delta x^2}.
\]
Second temporal derivatives: Approximate \(\frac{\partial^2 \psi}{\partial t^2}\) using central differences: \[
\frac{\partial^2 \psi}{\partial t^2} \approx \frac{\psi_i^{n+1} - 2\psi_i^n + \psi_i^{n-1}}{\Delta t^2}.
\]
Difference Equation
Substituting these into the wave equation, we obtain: \[
\frac{\psi_{i+1}^n - 2\psi_i^n + \psi_{i-1}^n}{\Delta x^2} = \frac{1}{v^2} \frac{\psi_i^{n+1} - 2\psi_i^n + \psi_i^{n-1}}{\Delta t^2}.
\]
where \(c = \frac{v \Delta t}{\Delta x}\) is the Courant number, which must satisfy the stability condition \(c \leq 1\).
Numerical Implementation
Initial state: A string fixed at both ends (\(\psi_0^n = \psi_N^n = 0\)) with an initial triangular displacement.
Time iteration: Compute the state \(\psi_i^{n+1}\) based on the states \(\psi_i^n\) and \(\psi_i^{n-1}\).
Visualization: Display several snapshots of the wave at different time intervals.
Next, I will prepare Python code to implement this algorithm.
The following code implements an explicit solution of the wave equation for a string fixed at both ends with an initial triangular displacement. The visualization shows the wave’s propagation at various time intervals.
Show the code
import numpy as npimport matplotlib.pyplot as plt# ParametersL =1.0# Length of the stringT =1.0# Total simulation timec =1.0# Wave speednx =100# Number of spatial pointsnt =500# Number of time stepsdx = L / (nx -1) # Spatial stepdt = T / nt # Time stepr = c * dt / dx # Courant number# Initialize arraysu = np.zeros((nt, nx)) # Solution at successive time stepsx = np.linspace(0, L, nx) # x-coordinates# Initial conditions: e.g., a sinusoidal-shaped initial displacementu[0, :] = np.exp(-100* (x -0.5)**2)u[1, :] = u[0, :]# Boundary conditions: u(0, t) = u(L, t) = 0 (string fixed at ends)u[:, 0] =0u[:, -1] =0# Time iterationfor n inrange(1, nt -1):for i inrange(1, nx -1): u[n +1, i] = (2* (1- r**2) * u[n, i] - u[n -1, i] + r**2* (u[n, i +1] + u[n, i -1]))# Select time snapshots for visualizationtime_snapshots = [0, 10, 50, 100, 200, 300]time_labels = [f'Time = {n*dt:.2f} s'for n in time_snapshots]# Plot snapshots at selected time intervalsplt.figure(figsize=(10, 6))for idx, n inenumerate(time_snapshots): plt.plot(x, u[n, :], label=time_labels[idx])plt.xlabel('Position on the string')plt.ylabel('Amplitude')plt.title('Wave propagation on a string at selected time intervals')plt.legend()plt.grid(True)plt.show()
same we can save in gif file
Intefeference of Waves
The interference of waves is a fascinating phenomenon that arises when two or more waves overlap in space and time. Depending on their relative phase and amplitude, the resulting interference can be constructive or destructive, leading to a variety of patterns and effects.
Constructive Interference
Constructive interference occurs when two waves are in phase, meaning their peaks and troughs align. In this case, the amplitudes of the waves add up, resulting in a wave with a larger amplitude. This reinforcement of the waves leads to a constructive interference pattern, where the combined wave appears stronger than the individual waves.
Destructive Interference
Destructive interference, on the other hand, arises when two waves are out of phase, with peaks aligning with troughs. In this scenario, the amplitudes of the waves cancel each other out, leading to a wave with a smaller amplitude or no wave at all. This destructive interference pattern results in regions of minimal or zero amplitude, where the waves effectively eliminate each other.
Superposition Principle
The interference of waves is governed by the superposition principle, which states that the total displacement of a medium at any point and time is the sum of the displacements caused by each individual wave. This principle allows us to predict the resulting interference pattern by analyzing the properties of the individual waves.
Visualization of Interference
Show the code
import numpy as npimport matplotlib.pyplot as plt# ParametersA1 =1.0# Amplitude of wave 1A2 =0.8# Amplitude of wave 2k1 =2.0# Wave number of wave 1k2 =2.5# Wave number of wave 2omega1 =1.0# Angular frequency of wave 1omega2 =1.0# Angular frequency of wave 2phi1 =0# Phase of wave 1phi2 = np.pi # Phase of wave 2t=0x = np.linspace(0, 8, 1000) # Range for x# Wave functionspsi1 = A1 * np.sin(k1 * x + omega1 * t + phi1)psi2 = A2 * np.sin(k2 * x + omega2 * t + phi2)psi_total = psi1 + psi2# Plot the wave functionsplt.figure(figsize=(12, 6))plt.plot(x, psi1, label="$\\psi_1(x) = A_1 \\sin(k_1 x - \\omega_1 t + \\phi_1)$", color="blue")plt.plot(x, psi2, label="$\\psi_2(x) = A_2 \\sin(k_2 x - \\omega_2 t + \\phi_2)$", color="red")plt.plot(x, psi_total, label="$\\psi_{\\text{total}}(x) = \\psi_1(x) + \\psi_2(x)$", color="green")# Add auxiliary linesplt.axhline(y=0, color='gray', linestyle='--', linewidth=0.7, alpha=0.5) # Horizontal axis# Configure axesplt.xlabel("Position $x$", fontsize=14)plt.ylabel("Wave function $\\psi(x)$", fontsize=14)# Add gridplt.grid(True, linestyle="--", alpha=0.7)# Display the plotplt.legend()plt.show()
In geogebra we can simulate the interference of two waves with different amplitudes, wave numbers, and phases. The resulting interference pattern is a combination of the individual waves, showcasing the superposition principle in action.
t=Slider[0, 6*pi, 0.1]
A1 = Slider[0.1, 2, 0.1]
A2 = Slider[0.1, 2, 0.1]
omega1 = Slider[0.1, 2, 0.1]
omega2 = Slider[0.1, 2, 0.1]
phi1 = Slider[0, 2*pi, 0.1]
phi2 = Slider[0, 2*pi, 0.1]
psi1 = A1 (k1 x + omega1 t + phi1)
psi2 = A2 (k2 x - omega2 t + phi2)
psi_total = psi1 + psi2
Huygens–Fresnel principle
The Huygens–Fresnel principle is a fundamental concept in wave optics that describes how every point on a wavefront can be considered as a source of secondary spherical waves. These secondary waves combine to form the wavefront at a later time, allowing us to predict the propagation of waves through various media and obstacles.
Refraction
Refraction is a common phenomenon where waves change direction as they pass from one medium to another. The Huygens–Fresnel principle provides a simple explanation for refraction, showing how the secondary waves generated at each point on the wavefront propagate through the new medium, leading to a change in the wave’s direction.
source: Wikipedia
Snell’s Law
Snell’s Law is a key result derived from the Huygens–Fresnel principle, describing the relationship between the angles of incidence and refraction for waves passing through different media. The law states that the ratio of the sines of the angles is equal to the ratio of the wave speeds in the two media:
where \(\theta_1\) and \(\theta_2\) are the angles of incidence and refraction, respectively, and \(v_1\) and \(v_2\) are the wave speeds in the two media.
Diffraction
Diffraction is another key concept explained by the Huygens–Fresnel principle, where waves bend around obstacles or pass through narrow openings. By considering each point on the wavefront as a source of secondary waves, we can predict how the diffracted waves will propagate and create interference patterns.
source: Wikipedia
source: Wikipedia
Doppler Effect
The Doppler effect is a well-known phenomenon where the frequency of a wave changes due to the relative motion between the source and observer. The Huygens–Fresnel principle provides a theoretical framework for understanding the Doppler effect, showing how the wavefronts shift and compress or expand based on the motion of the source and observer.
This effec can be visualized with the following animations (source: Wikipedia):
The vapor cone, also known as the shock collar or shock egg, is a visible cloud of condensed water droplets that can sometimes form around an object moving at high speeds. This phenomenon is often associated with supersonic aircraft and other high-speed vehicles, where the pressure difference between the front and rear of the object leads to the condensation of water vapor in the air.
A supersonic plane is flying at a speed greater than the speed of sound, emitting sound waves that reach an observer at a fixed time. The animation shows the plane’s trajectory, the sound waves emitted at different times, and the impulses that reach the observer simultaneously.
import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimationfrom IPython.display import HTML# Parametersc =1.0# Speed of sound [m/s]v =2.0# Speed of the plane (v > c) [m/s]T =5.0# Time at which all sound waves reach the observer [s]k = c / np.sqrt(v**2- c**2) # Spiral parameterimpulse_interval =0.5# Time between sound impulses [s]# Range of angles θ for the spiral (avoid division by zero as t → T)theta_max = (np.sqrt(v**2- c**2) / c) * np.log(T /1e-6) # Maximum angletheta = np.linspace(0, theta_max, 1000) # Angle range# Logarithmic spiral equationr_spiral = c * T * np.exp(-k * theta)# Convert to Cartesian coordinatesx_spiral = r_spiral * np.cos(theta)y_spiral = r_spiral * np.sin(theta)# Initialize the animationfig, ax = plt.subplots(figsize=(10, 10))ax.set_xlim(-c * T, c * T)ax.set_ylim(-c * T, c * T)ax.set_aspect('equal')ax.grid(True)ax.set_title("Supersonic Plane and Sound Waves Reaching the Observer Simultaneously")# Animation elementsplane, = ax.plot([], [], 'ko', markersize=8, label='Plane')sound_waves = ax.scatter([], [], color='grey', s=0.1, alpha=1, label='Sound Waves') # Use scatter for sound wavestrajectory, = ax.plot(x_spiral, y_spiral, 'b--', alpha=0.5, label='Plane Trajectory')observer = ax.plot(0, 0, 'kx', markersize=12, label='Observer')[0]time_text = ax.text(0.05, 0.95, '', transform=ax.transAxes)# List to store sound wave impulsesimpulses = []def init():"""Initialize the animation.""" plane.set_data([], []) sound_waves.set_offsets(np.empty((0, 2))) # Initialize scatter with empty data time_text.set_text('')return plane, sound_waves, time_textdef update(frame):"""Update the animation for each frame."""global impulses t_current = frame * T /100# Current time (0 to T)# Plane position at time t_current r_plane = c * (T - t_current) theta_plane = (np.sqrt(v**2- c**2) / c) * np.log(T / (T - t_current +1e-6)) x_plane = r_plane * np.cos(theta_plane) y_plane = r_plane * np.sin(theta_plane)# Sound wave positions (emitted earlier) t_emitted = np.linspace(0, t_current, 200) # Past emission times r_sound = c * (T - t_current) # Radius of sound waves at time t_current theta_sound = (np.sqrt(v**2- c**2) / c) * np.log(T / (T - t_emitted +1e-6)) x_sound = r_sound * np.cos(theta_sound) y_sound = r_sound * np.sin(theta_sound)# Update animation elements plane.set_data([x_plane], [y_plane]) # Ensure sequences are passed sound_waves.set_offsets(np.column_stack((x_sound, y_sound))) # Update scatter positions time_text.set_text(f'Time: {t_current:.1f}s / {T:.1f}s')# Add new sound impulses every 0.25 secondsif t_current % impulse_interval <0.05: # Check if 0.25 seconds have passed# Calculate the position from which the sound will reach (0,0) at time T t_emit = t_current # Emission time of the impulse r_emit = c * (T - t_emit) # Distance from the observer at emission time theta_emit = (np.sqrt(v**2- c**2) / c) * np.log(T / (T - t_emit +1e-6)) x_emit = r_emit * np.cos(theta_emit) y_emit = r_emit * np.sin(theta_emit) impulses.append({'time': t_emit, 'radius': 0, 'x': x_emit, 'y': y_emit})# Update existing impulsesfor impulse in impulses: impulse['radius'] += c * (T /100) # Increase the radius of the impulse# Draw impulsesfor impulse in impulses: circle = plt.Circle((impulse['x'], impulse['y']), impulse['radius'], color='r', fill=False, alpha=0.3) ax.add_artist(circle)# Remove impulses that are too large impulses = [impulse for impulse in impulses if impulse['radius'] < c * T]return plane, sound_waves, time_text# Create the animationani = FuncAnimation(fig, update, frames=100, init_func=init, blit=False, interval=50)# Display the animation in Google Colabplt.close() # Close the static plot to avoid showing it alongside the animationHTML(ani.to_html5_video())
Source Code
---title: Wavesformat: html: theme: flatly toc: true toc-depth: 3 highlight-style: tango code-line-numbers: true code-fold: true code-summary: "Show the code" code-tools: true code-block-bg: "rgba(42, 174, 42, 0.02)" code-block-border-left: "#2aae2a" code-language-label: true css: styles.css math: mathjax self-contained: true other-links: - text: Main page href: https://dchorazkiewicz.github.io/Mathematics_Physics_Lectures---## Springs and Mechanical WavesMechanical waves arise as a result of the application of simple harmonic motion rules to interconnected systems. At their core, such waves can be visualized as particles connected by springs, where each particle's motion influences the next. This elegant interplay between force, displacement, and energy transfer forms the foundation of mechanical wave dynamics.To illustrate this concept, imagine a chain of small masses connected by springs. When one mass is displaced, the motion propagates through the entire system, creating a wave-like pattern. You can explore this phenomenon in action with a simulation of ten masses linked by springs: * [Wave simulation 1](wave_exe_1.html)* [Wave simulation 2](wave_exe_2.html)## Plane Harmonic WaveA plane harmonic wave is a fundamental example of wave motion, described by a sinusoidal function such as:$$\psi(x, t) = A \sin(kx - \omega t + \phi),$$where:- $A$ is the amplitude,- $k$ is the wave number,- $\omega$ is the angular frequency,- $\phi$ is the phase constant,- $x$ and $t$ represent position and time, respectively.```{python}import numpy as npimport matplotlib.pyplot as plt# Parameters for the waveA =1.0# Amplitudelambda_wave =4.0# Wavelengthk =2* np.pi / lambda_wave # Wave numberphi =0# Phase constantx = np.linspace(0, 8, 1000) # Range for x# Wave functionpsi = A * np.sin(k * x - phi)# Plot the wave functionplt.figure(figsize=(12, 6))plt.plot(x, psi, label="$\\psi(x) = A \\sin(kx - \\phi)$", color="blue")# Mark the amplitudeplt.plot([lambda_wave /4, lambda_wave /4], [0, A], color="green", linewidth=2)plt.text(lambda_wave /4+0.2, A /2, r'Amplitude $A$', fontsize=12, ha='left', color="green")# Mark the segment from 1 to 5 with vertical lines at the endsx_start =1x_end =5y_label = A +0.3# Position above the wave to mark the segmentplt.plot([x_start, x_end], [y_label, y_label], color="red", linewidth=2) # Horizontal lineplt.plot([x_start, x_start], [y_label -0.05, y_label +0.05], color="red", linewidth=2) # Vertical line at startplt.plot([x_end, x_end], [y_label -0.05, y_label +0.05], color="red", linewidth=2) # Vertical line at endplt.text((x_start + x_end) /2, y_label -0.1, "$\\lambda$", fontsize=12, ha='center', color="red") # Label above the segment# Add auxiliary linesplt.axhline(y=0, color='gray', linestyle='--', linewidth=0.7, alpha=0.5) # Horizontal axisplt.axhline(y=A, color='gray', linestyle='--', linewidth=0.7) # Amplitude lineplt.axhline(y=-A, color='gray', linestyle='--', linewidth=0.7) # Negative amplitude line# Configure axesplt.xlabel("Position $x$", fontsize=14)plt.ylabel("Wave function $\\psi(x)$", fontsize=14)# Add gridplt.grid(True, linestyle="--", alpha=0.7)# Display the plotplt.show()```### Constructing the Wave EquationThe temporal and spatial derivatives of the wave function $\psi(x, t)$ are key to understanding its behavior. The first and second derivatives with respect to time $t$ are:$$\frac{\partial \psi}{\partial t} = -A \omega \cos(kx - \omega t + \phi),$$$$\frac{\partial^2 \psi}{\partial t^2} = -A \omega^2 \sin(kx - \omega t + \phi).$$Similarly, the first and second derivatives with respect to position $x$ are:$$\frac{\partial \psi}{\partial x} = A k \cos(kx - \omega t + \phi),$$$$\frac{\partial^2 \psi}{\partial x^2} = -A k^2 \sin(kx - \omega t + \phi).$$By combining these derivatives, we can see how the wave function satisfies the general wave equation. Substituting $\frac{\partial^2 \psi}{\partial x^2}$ and $\frac{\partial^2 \psi}{\partial t^2}$ into:$$\frac{\partial^2 \psi}{\partial x^2} = \frac{1}{v^2} \frac{\partial^2 \psi}{\partial t^2},$$and using the relations $v = \frac{\omega}{k}$, it becomes clear that the sinusoidal wave satisfies this fundamental equation, connecting temporal and spatial changes in the wave function.### General ImplicationsWhat we have derived here is not just a coincidence but is, in fact, the result of more general considerations. The equation we obtained, often called the wave equation, emerges from the fundamental principles governing wave phenomena. It describes the behavior of a wide range of wave-like systems, including sound waves, water waves, and even electromagnetic waves in certain contexts. As such, it is recognized as one of the cornerstone equations in the study of physical systems exhibiting wave motion.Let us begin! First, we will derive the difference equations that allow for the numerical solution of the wave equation. Here is the plan:### Difference Equation for the Wave EquationRecall the wave equation in the form:$$\frac{\partial^2 \psi}{\partial x^2} = \frac{1}{v^2} \frac{\partial^2 \psi}{\partial t^2}.$$#### Discretization of Space and TimeAssume that:- We divide the space $x$ into $N$ equal intervals of length $\Delta x$.- We divide the time $t$ into steps of length $\Delta t$.The function $\psi(x, t)$ is replaced by a discrete grid $\psi_i^n$, where $i$ denotes the spatial index and $n$ denotes the time index:- $i = 0, 1, 2, \dots, N$,- $n = 0, 1, 2, \dots$.#### Finite Difference Approximations1. **Second spatial derivatives**: Approximate $\frac{\partial^2 \psi}{\partial x^2}$ using central differences: $$ \frac{\partial^2 \psi}{\partial x^2} \approx \frac{\psi_{i+1}^n - 2\psi_i^n + \psi_{i-1}^n}{\Delta x^2}. $$2. **Second temporal derivatives**: Approximate $\frac{\partial^2 \psi}{\partial t^2}$ using central differences: $$ \frac{\partial^2 \psi}{\partial t^2} \approx \frac{\psi_i^{n+1} - 2\psi_i^n + \psi_i^{n-1}}{\Delta t^2}. $$#### Difference EquationSubstituting these into the wave equation, we obtain:$$\frac{\psi_{i+1}^n - 2\psi_i^n + \psi_{i-1}^n}{\Delta x^2} = \frac{1}{v^2} \frac{\psi_i^{n+1} - 2\psi_i^n + \psi_i^{n-1}}{\Delta t^2}.$$Simplifying, we solve for $\psi_i^{n+1}$:$$\psi_i^{n+1} = 2\psi_i^n - \psi_i^{n-1} + c^2 \left( \psi_{i+1}^n - 2\psi_i^n + \psi_{i-1}^n \right),$$where $c = \frac{v \Delta t}{\Delta x}$ is the Courant number, which must satisfy the stability condition $c \leq 1$.---### Numerical Implementation1. **Initial state**: A string fixed at both ends ($\psi_0^n = \psi_N^n = 0$) with an initial triangular displacement.2. **Time iteration**: Compute the state $\psi_i^{n+1}$ based on the states $\psi_i^n$ and $\psi_i^{n-1}$.3. **Visualization**: Display several snapshots of the wave at different time intervals.Next, I will prepare Python code to implement this algorithm.The following code implements an explicit solution of the wave equation for a string fixed at both ends with an initial triangular displacement. The visualization shows the wave's propagation at various time intervals.```{python}import numpy as npimport matplotlib.pyplot as plt# ParametersL =1.0# Length of the stringT =1.0# Total simulation timec =1.0# Wave speednx =100# Number of spatial pointsnt =500# Number of time stepsdx = L / (nx -1) # Spatial stepdt = T / nt # Time stepr = c * dt / dx # Courant number# Initialize arraysu = np.zeros((nt, nx)) # Solution at successive time stepsx = np.linspace(0, L, nx) # x-coordinates# Initial conditions: e.g., a sinusoidal-shaped initial displacementu[0, :] = np.exp(-100* (x -0.5)**2)u[1, :] = u[0, :]# Boundary conditions: u(0, t) = u(L, t) = 0 (string fixed at ends)u[:, 0] =0u[:, -1] =0# Time iterationfor n inrange(1, nt -1):for i inrange(1, nx -1): u[n +1, i] = (2* (1- r**2) * u[n, i] - u[n -1, i] + r**2* (u[n, i +1] + u[n, i -1]))# Select time snapshots for visualizationtime_snapshots = [0, 10, 50, 100, 200, 300]time_labels = [f'Time = {n*dt:.2f} s'for n in time_snapshots]# Plot snapshots at selected time intervalsplt.figure(figsize=(10, 6))for idx, n inenumerate(time_snapshots): plt.plot(x, u[n, :], label=time_labels[idx])plt.xlabel('Position on the string')plt.ylabel('Amplitude')plt.title('Wave propagation on a string at selected time intervals')plt.legend()plt.grid(True)plt.show()```same we can save in gif file## Intefeference of WavesThe interference of waves is a fascinating phenomenon that arises when two or more waves overlap in space and time. Depending on their relative phase and amplitude, the resulting interference can be constructive or destructive, leading to a variety of patterns and effects.### Constructive InterferenceConstructive interference occurs when two waves are in phase, meaning their peaks and troughs align. In this case, the amplitudes of the waves add up, resulting in a wave with a larger amplitude. This reinforcement of the waves leads to a constructive interference pattern, where the combined wave appears stronger than the individual waves.### Destructive InterferenceDestructive interference, on the other hand, arises when two waves are out of phase, with peaks aligning with troughs. In this scenario, the amplitudes of the waves cancel each other out, leading to a wave with a smaller amplitude or no wave at all. This destructive interference pattern results in regions of minimal or zero amplitude, where the waves effectively eliminate each other.### Superposition PrincipleThe interference of waves is governed by the superposition principle, which states that the total displacement of a medium at any point and time is the sum of the displacements caused by each individual wave. This principle allows us to predict the resulting interference pattern by analyzing the properties of the individual waves.### Visualization of Interference```{python}import numpy as npimport matplotlib.pyplot as plt# ParametersA1 =1.0# Amplitude of wave 1A2 =0.8# Amplitude of wave 2k1 =2.0# Wave number of wave 1k2 =2.5# Wave number of wave 2omega1 =1.0# Angular frequency of wave 1omega2 =1.0# Angular frequency of wave 2phi1 =0# Phase of wave 1phi2 = np.pi # Phase of wave 2t=0x = np.linspace(0, 8, 1000) # Range for x# Wave functionspsi1 = A1 * np.sin(k1 * x + omega1 * t + phi1)psi2 = A2 * np.sin(k2 * x + omega2 * t + phi2)psi_total = psi1 + psi2# Plot the wave functionsplt.figure(figsize=(12, 6))plt.plot(x, psi1, label="$\\psi_1(x) = A_1 \\sin(k_1 x - \\omega_1 t + \\phi_1)$", color="blue")plt.plot(x, psi2, label="$\\psi_2(x) = A_2 \\sin(k_2 x - \\omega_2 t + \\phi_2)$", color="red")plt.plot(x, psi_total, label="$\\psi_{\\text{total}}(x) = \\psi_1(x) + \\psi_2(x)$", color="green")# Add auxiliary linesplt.axhline(y=0, color='gray', linestyle='--', linewidth=0.7, alpha=0.5) # Horizontal axis# Configure axesplt.xlabel("Position $x$", fontsize=14)plt.ylabel("Wave function $\\psi(x)$", fontsize=14)# Add gridplt.grid(True, linestyle="--", alpha=0.7)# Display the plotplt.legend()plt.show()```In geogebra we can simulate the interference of two waves with different amplitudes, wave numbers, and phases. The resulting interference pattern is a combination of the individual waves, showcasing the superposition principle in action.:::{.geogebra-instruction}* t=Slider[0, 6*pi, 0.1]* A1 = Slider[0.1, 2, 0.1]* A2 = Slider[0.1, 2, 0.1]* omega1 = Slider[0.1, 2, 0.1]* omega2 = Slider[0.1, 2, 0.1]* phi1 = Slider[0, 2*pi, 0.1]* phi2 = Slider[0, 2*pi, 0.1]* psi1 = A1 \sin(k1 x + omega1 t + phi1)* psi2 = A2 \sin(k2 x - omega2 t + phi2)* psi_total = psi1 + psi2:::## Huygens–Fresnel principleThe Huygens–Fresnel principle is a fundamental concept in wave optics that describes how every point on a wavefront can be considered as a source of secondary spherical waves. These secondary waves combine to form the wavefront at a later time, allowing us to predict the propagation of waves through various media and obstacles.### RefractionRefraction is a common phenomenon where waves change direction as they pass from one medium to another. The Huygens–Fresnel principle provides a simple explanation for refraction, showing how the secondary waves generated at each point on the wavefront propagate through the new medium, leading to a change in the wave's direction.#### Snell's LawSnell's Law is a key result derived from the Huygens–Fresnel principle, describing the relationship between the angles of incidence and refraction for waves passing through different media. The law states that the ratio of the sines of the angles is equal to the ratio of the wave speeds in the two media:$$\frac{\sin(\theta_1)}{\sin(\theta_2)} = \frac{v_1}{v_2},$$where $\theta_1$ and $\theta_2$ are the angles of incidence and refraction, respectively, and $v_1$ and $v_2$ are the wave speeds in the two media.### DiffractionDiffraction is another key concept explained by the Huygens–Fresnel principle, where waves bend around obstacles or pass through narrow openings. By considering each point on the wavefront as a source of secondary waves, we can predict how the diffracted waves will propagate and create interference patterns.{width=50%}## Doppler EffectThe Doppler effect is a well-known phenomenon where the frequency of a wave changes due to the relative motion between the source and observer. The Huygens–Fresnel principle provides a theoretical framework for understanding the Doppler effect, showing how the wavefronts shift and compress or expand based on the motion of the source and observer.This effec can be visualized with the following animations (source: Wikipedia)::::{layout-ncol="2"}:::#### Vapor cone ([Wikipedia](https://en.wikipedia.org/wiki/Vapor_cone))The vapor cone, also known as the shock collar or shock egg, is a visible cloud of condensed water droplets that can sometimes form around an object moving at high speeds. This phenomenon is often associated with supersonic aircraft and other high-speed vehicles, where the pressure difference between the front and rear of the object leads to the condensation of water vapor in the air.#### Playground for waves:- [Wave applet](https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_all.html)- [Heat versus Wave Equation](https://x.com/gabrielpeyre/status/1765255995809305064?t=pzuMHd7gpN1penkJplRkQg)- [Video of Doppler Effect on the street](https://youtu.be/ffg4TOpXZyg?si=PxLSJtInPxolERYb)- [Doppler Effect simulator](https://ophysics.com/waves11.html)- [Interference applet](https://phet.colorado.edu/sims/html/wave-interference/latest/wave-interference_all.html)## Cummulative waveA supersonic plane is flying at a speed greater than the speed of sound, emitting sound waves that reach an observer at a fixed time. The animation shows the plane's trajectory, the sound waves emitted at different times, and the impulses that reach the observer simultaneously.```pythonimport numpy as npimport matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimationfrom IPython.display import HTML# Parametersc =1.0# Speed of sound [m/s]v =2.0# Speed of the plane (v > c) [m/s]T =5.0# Time at which all sound waves reach the observer [s]k = c / np.sqrt(v**2- c**2) # Spiral parameterimpulse_interval =0.5# Time between sound impulses [s]# Range of angles θ for the spiral (avoid division by zero as t → T)theta_max = (np.sqrt(v**2- c**2) / c) * np.log(T /1e-6) # Maximum angletheta = np.linspace(0, theta_max, 1000) # Angle range# Logarithmic spiral equationr_spiral = c * T * np.exp(-k * theta)# Convert to Cartesian coordinatesx_spiral = r_spiral * np.cos(theta)y_spiral = r_spiral * np.sin(theta)# Initialize the animationfig, ax = plt.subplots(figsize=(10, 10))ax.set_xlim(-c * T, c * T)ax.set_ylim(-c * T, c * T)ax.set_aspect('equal')ax.grid(True)ax.set_title("Supersonic Plane and Sound Waves Reaching the Observer Simultaneously")# Animation elementsplane, = ax.plot([], [], 'ko', markersize=8, label='Plane')sound_waves = ax.scatter([], [], color='grey', s=0.1, alpha=1, label='Sound Waves') # Use scatter for sound wavestrajectory, = ax.plot(x_spiral, y_spiral, 'b--', alpha=0.5, label='Plane Trajectory')observer = ax.plot(0, 0, 'kx', markersize=12, label='Observer')[0]time_text = ax.text(0.05, 0.95, '', transform=ax.transAxes)# List to store sound wave impulsesimpulses = []def init():"""Initialize the animation.""" plane.set_data([], []) sound_waves.set_offsets(np.empty((0, 2))) # Initialize scatter with empty data time_text.set_text('')return plane, sound_waves, time_textdef update(frame):"""Update the animation for each frame."""global impulses t_current = frame * T /100# Current time (0 to T)# Plane position at time t_current r_plane = c * (T - t_current) theta_plane = (np.sqrt(v**2- c**2) / c) * np.log(T / (T - t_current +1e-6)) x_plane = r_plane * np.cos(theta_plane) y_plane = r_plane * np.sin(theta_plane)# Sound wave positions (emitted earlier) t_emitted = np.linspace(0, t_current, 200) # Past emission times r_sound = c * (T - t_current) # Radius of sound waves at time t_current theta_sound = (np.sqrt(v**2- c**2) / c) * np.log(T / (T - t_emitted +1e-6)) x_sound = r_sound * np.cos(theta_sound) y_sound = r_sound * np.sin(theta_sound)# Update animation elements plane.set_data([x_plane], [y_plane]) # Ensure sequences are passed sound_waves.set_offsets(np.column_stack((x_sound, y_sound))) # Update scatter positions time_text.set_text(f'Time: {t_current:.1f}s / {T:.1f}s')# Add new sound impulses every 0.25 secondsif t_current % impulse_interval <0.05: # Check if 0.25 seconds have passed# Calculate the position from which the sound will reach (0,0) at time T t_emit = t_current # Emission time of the impulse r_emit = c * (T - t_emit) # Distance from the observer at emission time theta_emit = (np.sqrt(v**2- c**2) / c) * np.log(T / (T - t_emit +1e-6)) x_emit = r_emit * np.cos(theta_emit) y_emit = r_emit * np.sin(theta_emit) impulses.append({'time': t_emit, 'radius': 0, 'x': x_emit, 'y': y_emit})# Update existing impulsesfor impulse in impulses: impulse['radius'] += c * (T /100) # Increase the radius of the impulse# Draw impulsesfor impulse in impulses: circle = plt.Circle((impulse['x'], impulse['y']), impulse['radius'], color='r', fill=False, alpha=0.3) ax.add_artist(circle)# Remove impulses that are too large impulses = [impulse for impulse in impulses if impulse['radius'] < c * T]return plane, sound_waves, time_text# Create the animationani = FuncAnimation(fig, update, frames=100, init_func=init, blit=False, interval=50)# Display the animation in Google Colabplt.close() # Close the static plot to avoid showing it alongside the animationHTML(ani.to_html5_video())```