diff --git a/doc/examples/wfs-animation.ipynb b/doc/examples/wfs-animation.ipynb new file mode 100644 index 00000000..0b01f27a --- /dev/null +++ b/doc/examples/wfs-animation.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "77fc3672", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import sfs\n", + "from matplotlib import animation\n", + "from IPython.display import HTML\n", + "from functools import partial\n", + "from scipy.signal import unit_impulse\n", + "\n", + "\n", + "# Point source\n", + "xs = 0, 2, 0\n", + "rs = np.linalg.norm(xs) # distance from origin\n", + "ts = rs / sfs.default.c # time-of-arrival at origin\n", + "\n", + "# Impulsive excitation\n", + "fs = 8000 # Adjust this to change the shape (width) of the impulse\n", + "signal = unit_impulse(512), fs # Band-limited pulse (e.g. sinc) can be used instead\n", + "\n", + "# Circular loudspeaker array\n", + "N = 32 # number of loudspeakers\n", + "R = 1.5 # radius\n", + "array = sfs.array.circular(N, R)\n", + "\n", + "grid = sfs.util.xyz_grid([-2, 2], [-2, 2], 0, spacing=0.02)\n", + "\n", + "delays, weights, selection, secondary_source = \\\n", + " sfs.td.wfs.point_25d(array.x, array.n, xs)\n", + "d = sfs.td.wfs.driving_signals(delays, weights, signal)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3560c30", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# Animation\n", + "def plot(d, selection, secondary_source, t=0, ax=None, **kw):\n", + " p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,\n", + " observation_time=t)\n", + " im = sfs.plot2d.amplitude(p, grid, ax=ax, **kw)\n", + " sfs.plot2d.loudspeakers(array.x, array.n, selection * array.a, size=0.15)\n", + " return im\n", + "\n", + "def update_frame_pressure(i, time_stamps):\n", + " t_i = time_stamps[i]\n", + " p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,\n", + " observation_time=t_i)\n", + " im.set_array(p)\n", + " return [im]\n", + "\n", + "\n", + "time_stamps = np.linspace(0.5/343, 5/343, 100) # Time sampling is different from fs defined above\n", + "frames = 100\n", + "interval = 150\n", + "\n", + "\n", + "fig, ax = plt.subplots(figsize=(5, 5))\n", + "p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,\n", + " observation_time=0)\n", + "im = plot(d, selection, secondary_source, t=ts, ax=ax, vmin=-0.01, vmax=0.01)\n", + "\n", + "ani = animation.FuncAnimation(\n", + " fig, partial(update_frame_pressure, time_stamps=time_stamps),\n", + " frames=frames, interval=interval, blit=True)\n", + "plt.close()\n", + "HTML(ani.to_jshtml())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f77a060", + "metadata": {}, + "outputs": [], + "source": [ + "# Save as gif file - This might take a few minutes.\n", + "ani.save(\"wfs-25d-td.gif\", writer='imagemagick',fps=10, dpi=200)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}