Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pulsating sphere #69

Merged
merged 1 commit into from
Mar 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ addons:
apt:
packages:
- pandoc
- ffmpeg
install:
- pip install .
- pip install -r tests/requirements.txt
Expand Down
1 change: 1 addition & 0 deletions doc/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ Examples

examples/modal-room-acoustics
examples/mirror-image-source-model
examples/animations-pulsating-sphere
example-python-scripts
366 changes: 366 additions & 0 deletions doc/examples/animations-pulsating-sphere.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Animations of a Pulsating Sphere"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sfs\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from IPython.display import HTML"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example, the sound field of a pulsating sphere is visualized.\n",
"Different acoustic variables, such as sound pressure,\n",
"particle velocity, and particle displacement, are simulated.\n",
"The first two quantities are computed with\n",
"\n",
"- [sfs.mono.source.pulsating_sphere()](../sfs.mono.source.rst#sfs.mono.source.pulsating_sphere) and \n",
"- [sfs.mono.source.pulsating_sphere_velocity()](../sfs.mono.source.rst#sfs.mono.source.pulsating_sphere_velocity)\n",
"\n",
"while the last one can be obtained by using\n",
"\n",
"- [sfs.util.displacement()](../sfs.util.rst#sfs.util.displacement)\n",
"\n",
"which converts the particle velocity into displacement.\n",
"\n",
"A couple of additional functions are implemented in\n",
"\n",
"- [animations_pulsating_sphere.py](animations_pulsating_sphere.py)\n",
"\n",
"in order to help creating animating pictures, which is fun!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import animations_pulsating_sphere as animation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Pulsating sphere\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments at the beginning of a cell can typically be moved to a Markdown cell before the code cell.

Or they can be removed if they are meaningless.

"center = [0, 0, 0]\n",
"radius = 0.25\n",
"amplitude = 0.05\n",
"f = 1000 # frequency\n",
"omega = 2 * np.pi * f # angular frequency\n",
"\n",
"# Axis limits\n",
"figsize = (6, 6)\n",
"xmin, xmax = -1, 1\n",
"ymin, ymax = -1, 1\n",
"\n",
"# Animations\n",
"frames = 20 # frames per period"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Particle Displacement"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"grid = sfs.util.xyz_grid([xmin, xmax], [ymin, ymax], 0, spacing=0.025)\n",
"ani = animation.particle_displacement(\n",
" omega, center, radius, amplitude, grid, frames, figsize, c='Gray')\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can play with the animation more interactively by using `.to_jshtml`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"HTML(ani.to_jshtml())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Of course, different types of grid can be chosen.\n",
"Below is the particle animation using the same parameters\n",
"but with a [hexagonal grid](https://www.redblobgames.com/grids/hexagons/)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def hex_grid(xlim, ylim, hex_edge, align='horizontal'):\n",
" if align is 'vertical':\n",
" umin, umax = ylim\n",
" vmin, vmax = xlim\n",
" else:\n",
" umin, umax = xlim\n",
" vmin, vmax = ylim\n",
" du = np.sqrt(3) * hex_edge\n",
" dv = 1.5 * hex_edge\n",
" num_u = int((umax - umin) / du)\n",
" num_v = int((vmax - vmin) / dv)\n",
" u, v = np.meshgrid(np.linspace(umin, umax, num_u),\n",
" np.linspace(vmin, vmax, num_v))\n",
" u[::2] += 0.5 * du\n",
"\n",
" if align is 'vertical':\n",
" grid = v, u, 0\n",
" elif align is 'horizontal':\n",
" grid = u, v, 0\n",
" return grid"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"grid = hex_grid([xmin, xmax], [ymin, ymax], 0.0125, 'vertical')\n",
"ani = animation.particle_displacement(\n",
" omega, center, radius, amplitude, grid, frames, figsize, c='Gray')\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Another one using a random grid."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"grid = [np.random.uniform(xmin, xmax, 4000),\n",
" np.random.uniform(ymin, ymax, 4000), 0]\n",
"ani = animation.particle_displacement(\n",
" omega, center, radius, amplitude, grid, frames, figsize, c='Gray')\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Each grid has its strengths and weaknesses. Please refer to the\n",
"[on-line discussion](https://github.com/sfstoolbox/sfs-python/pull/69#issuecomment-468405536)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Particle Velocity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"amplitude = 1e-3\n",
"grid = sfs.util.xyz_grid([xmin, xmax], [ymin, ymax], 0, spacing=0.04)\n",
"ani = animation.particle_velocity(\n",
" omega, center, radius, amplitude, grid, frames, figsize)\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Please notice that the amplitude of the pulsating motion is adjusted\n",
"so that the arrows are neither too short nor too long.\n",
"This kind of compromise is inevitable since\n",
"\n",
"$$\n",
"\\text{(particle velocity)} = \\text{i} \\omega \\times (\\text{amplitude}),\n",
"$$\n",
"\n",
"thus the absolute value of particle velocity is usually\n",
"much larger than that of amplitude.\n",
"It should be also kept in mind that the hole in the middle\n",
"does not visualizes the exact motion of the pulsating sphere.\n",
"According to the above equation, the actual amplitude should be\n",
"much smaller than the arrow lengths.\n",
"The changing rate of its size is also two times higher than the original frequency."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sound Pressure"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"amplitude = 0.05\n",
"impedance_pw = sfs.default.rho0 * sfs.default.c\n",
"max_pressure = omega * impedance_pw * amplitude\n",
"\n",
"grid = sfs.util.xyz_grid([xmin, xmax], [ymin, ymax], 0, spacing=0.005)\n",
"ani = animation.sound_pressure(\n",
" omega, center, radius, amplitude, grid, frames, pulsate=True,\n",
" figsize=figsize, vmin=-max_pressure, vmax=max_pressure)\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that the sound pressure exceeds\n",
"the atmospheric pressure ($\\approx 10^5$ Pa), which of course makes no sense.\n",
"This is due to the large amplitude (50 mm) of the pulsating motion.\n",
"It was chosen to better visualize the particle movements\n",
"in the earlier animations.\n",
"\n",
"For 1 kHz, the amplitude corresponding to a moderate sound pressure,\n",
"let say 1 Pa, is in the order of micrometer.\n",
"As it is very small compared to the corresponding wavelength (0.343 m),\n",
"the movement of the particles and the spatial structure of the sound field\n",
"cannot be observed simultaneously.\n",
"Furthermore, at high frequencies, the sound pressure\n",
"for a given particle displacement scales with the frequency.\n",
"The smaller wavelength (higher frequency) we choose,\n",
"it is more likely to end up with a prohibitively high sound pressure.\n",
"\n",
"In the following examples, the amplitude is set to a realistic value 1 $\\mu$m.\n",
"Notice that the pulsating motion of the sphere is no more visible."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"amplitude = 1e-6\n",
"impedance_pw = sfs.default.rho0 * sfs.default.c\n",
"max_pressure = omega * impedance_pw * amplitude\n",
"\n",
"grid = sfs.util.xyz_grid([xmin, xmax], [ymin, ymax], 0, spacing=0.005)\n",
"ani = animation.sound_pressure(\n",
" omega, center, radius, amplitude, grid, frames, pulsate=True,\n",
" figsize=figsize, vmin=-max_pressure, vmax=max_pressure)\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's zoom in closer to the boundary of the sphere."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = 10 * amplitude\n",
"xmin_zoom, xmax_zoom = radius - L, radius + L\n",
"ymin_zoom, ymax_zoom = -L, L"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"grid = sfs.util.xyz_grid([xmin_zoom, xmax_zoom], [ymin_zoom, ymax_zoom], 0, spacing=L / 100)\n",
"ani = animation.sound_pressure(\n",
" omega, center, radius, amplitude, grid, frames, pulsate=True,\n",
" figsize=figsize, vmin=-max_pressure, vmax=max_pressure)\n",
"plt.close()\n",
"HTML(ani.to_html5_video())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This shows how the vibrating motion of the sphere (left half)\n",
"changes the sound pressure of the surrounding air (right half).\n",
"Notice that the sound pressure increases/decreases (more red/blue)\n",
"when the surface accelerates/decelerates."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python [default]",
"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.5.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading