user13794156
user13794156

Reputation:

Matplotlib interference figure strange pattern

I am trying to make an interference figure animation like this one:

enter image description here

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()

enter image description here

The issue is that strange patterns appear like in the last frames:

enter image description here

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

Answers (1)

Zephyr
Zephyr

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()

enter image description here

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

Related Questions