Reputation:
I am trying to make an interference figure animation like this one:
The difference is that the above image shows the interference figure over time, so the constructive and destructive interference points remain fixed. On the contrary, I am trying to make an animation where I change the frequency of the two sources, keeping them fixed in the space.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
source = 0.5
sources = [-source, source]
axlim = max(sources)*2 + 1
N = 1000
x = np.linspace(-axlim, axlim, N)
y = np.linspace(-axlim, axlim, N)
X, Y = np.meshgrid(x, y)
fig = plt.figure()
def update(f):
plt.gca().cla()
C1 = np.sin(2*np.pi*f*((X - sources[0])**2 + Y**2))
C2 = np.sin(2*np.pi*f*((X - sources[1])**2 + Y**2))
Z = C1 + C2
plt.contour(X, Y, Z)
plt.plot(sources, [0, 0], 'ro')
plt.gca().set_aspect('equal')
plt.axis('off')
ani = FuncAnimation(fig = fig, func = update, frames = 11, interval = 100)
plt.show()
The issue is that strange patterns appear like in the last frames:
those patterns are not physical (they are not consistent with physics' laws), so there must be an error in my code. I cannot find out where, but I think the issue is in the matplotlib contour
function: I suspect it introduce a sort of aliasing...
Upvotes: 2
Views: 2917
Reputation: 12496
The issue is in your definition of C1
and C2
: you apply the sinusoidal function to the sum of the squared x and y distances, without applying a squared root. You should use:
C1 = np.sin(2*np.pi*f*np.sqrt((X - sources[0])**2 + Y**2))
C2 = np.sin(2*np.pi*f*np.sqrt((X - sources[1])**2 + Y**2))
There is no issue with the contour
plot method, however, I suggest you to replace it with contourf
or, even better, imshow
. The reason is that contour
plot lines where your field has the same value, keeping the rest of the plot empty. On the contrary, contourf
or imshow
fill the empty space with the colormap you choose, so you can display your field in a better way and avoid ambiguous white spaces.
See this code for reference:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.animation import FuncAnimation
source = 0.5
sources = [-source, source]
axlim = max(sources)*2 + 1
N = 1000
x = np.linspace(-axlim, axlim, N)
y = np.linspace(-axlim, axlim, N)
X, Y = np.meshgrid(x, y)
norm = plt.Normalize(-2, 2)
cmap = LinearSegmentedColormap.from_list('', ['black', 'white', 'black'])
fig, ax = plt.subplots()
def update(f):
ax.cla()
C1 = np.sin(2*np.pi*f*np.sqrt((X - sources[0])**2 + Y**2))
C2 = np.sin(2*np.pi*f*np.sqrt((X - sources[1])**2 + Y**2))
Z = C1 + C2
ax.imshow(Z,
cmap = cmap,
norm = norm)
ax.plot(N/2*(1 + source/axlim), N/2, 'ro')
ax.plot(N/2*(1 - source/axlim), N/2, 'ro')
ax.set_title(f'f = {f} Hz')
ax.set_aspect('equal')
ax.axis('off')
ani = FuncAnimation(fig = fig, func = update, frames = 11, interval = 100)
plt.show()
Since peaks and valleys of your field are both constructive interference points, while in the destructive points the field is null, I chose a black - white - black colormap, you cannot distinguish peaks from valleys but it is easier to distinguish constructive from destructive interference points.
Upvotes: 2