-
Notifications
You must be signed in to change notification settings - Fork 20
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
Pulsating sphere #69
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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", | ||
"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 | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.