This page was generated from doc/examples/wfs-animation.ipynb.
Interactive online version:
[1]:
import matplotlib.pyplot as plt
import numpy as np
import sfs
from matplotlib import animation
from IPython.display import HTML
from functools import partial
from scipy.signal import unit_impulse
# Point source
xs = 0, 2, 0
rs = np.linalg.norm(xs) # distance from origin
ts = rs / sfs.default.c # time-of-arrival at origin
# Impulsive excitation
fs = 8000 # Adjust this to change the shape (width) of the impulse
signal = unit_impulse(512), fs # Band-limited pulse (e.g. sinc) can be used instead
# Circular loudspeaker array
N = 32 # number of loudspeakers
R = 1.5 # radius
array = sfs.array.circular(N, R)
grid = sfs.util.xyz_grid([-2, 2], [-2, 2], 0, spacing=0.02)
delays, weights, selection, secondary_source = \
sfs.td.wfs.point_25d(array.x, array.n, xs)
d = sfs.td.wfs.driving_signals(delays, weights, signal)
[2]:
# Animation
def plot(d, selection, secondary_source, t=0, ax=None, **kw):
p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,
observation_time=t)
im = sfs.plot2d.amplitude(p, grid, ax=ax, **kw)
sfs.plot2d.loudspeakers(array.x, array.n, selection * array.a, size=0.15)
return im
def update_frame_pressure(i, time_stamps):
t_i = time_stamps[i]
p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,
observation_time=t_i)
im.set_array(p)
return [im]
time_stamps = np.linspace(0.5/343, 5/343, 100) # Time sampling is different from fs defined above
frames = 100
interval = 150
fig, ax = plt.subplots(figsize=(5, 5))
p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,
observation_time=0)
im = plot(d, selection, secondary_source, t=ts, ax=ax, vmin=-0.01, vmax=0.01)
ani = animation.FuncAnimation(
fig, partial(update_frame_pressure, time_stamps=time_stamps),
frames=frames, interval=interval, blit=True)
plt.close()
HTML(ani.to_jshtml())
[2]:
[3]:
# Save as gif file - This might take a few minutes.
ani.save("wfs-25d-td.gif", writer='imagemagick',fps=10, dpi=200)