-
Notifications
You must be signed in to change notification settings - Fork 20
Animation of time-domain WFS #193
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
base: master
Are you sure you want to change the base?
Conversation
Cool, I remember those plots ;) |
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.
You should add your example to doc/examples.rst
(and give it a title), so that it appears in our brand-new example gallery: https://sfs-python--193.org.readthedocs.build/en/193/examples.html
Here's how it looks in the docs: https://sfs-python--193.org.readthedocs.build/en/193/examples/wfs-animation.html
" return [im]\n", | ||
"\n", | ||
"\n", | ||
"time_stamps = np.linspace(0.5/343, 5/343, 100) # Time sampling is different from fs defined above\n", |
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.
The number 343
is suspicious here. If you want to use the speed of sound, you should use sfs.default.c
, if not, it would probably be better to use different values.
"\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", |
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.
Is unit_impulse
really necessary here? What about using this?
signal = [1], fs
"p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,\n", | ||
" observation_time=0)\n", |
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.
I don't think that this does anything, right?
"p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,\n", | |
" observation_time=0)\n", |
It just creates p
which is then never used?
"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", |
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.
It is a bit strange that you use partial function application here, when you have full control over the function. You could simply move the time_stamps
into the function.
But even better, you could use the time_stamps
as frames
:
def update_frame_pressure(t):
p = sfs.td.synthesize(
d, selection, array, secondary_source, grid=grid, observation_time=t)
im.set_array(p)
return [im]
ani = animation.FuncAnimation(
fig, update_frame_pressure, frames=time_stamps,
interval=interval, blit=True)
"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", |
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.
This frame is not used in the final animation, so the value of t
is not really relevant, and defining ts
is not necessary.
"outputs": [], | ||
"source": [ | ||
"# Animation\n", | ||
"def plot(d, selection, secondary_source, t=0, ax=None, **kw):\n", |
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.
In general, I'm a fan of reusable plot functions, especially if users can copy it and use it in their own code. However, this doesn't work here, because grid
and array
are not passed as function arguments.
I'm also not sure if it helps the understanding here, in the context of the animation, what do you think?
I think you should either add more arguments or completely dissolve the function. I could imagine a few notebook cells with easily digestible steps like this:
Create loudspeaker driving signals.
delays, weights, selection, secondary_source = sfs.td.wfs.point_25d(
array.x, array.n, xs)
d = sfs.td.wfs.driving_signals(delays, weights, signal)
Create one frame of the initial sound field for the initial plot.
The observation_time
doesn't matter,
because this frame will not be used in the final animation.
p = sfs.td.synthesize(
d, selection, array, secondary_source, grid=grid, observation_time=0)
Create the initial plot (but don't show it yet).
fig, ax = plt.subplots(figsize=(5, 5))
im = sfs.plot2d.amplitude(p, grid, ax=ax, vmin=-0.01, vmax=0.01)
sfs.plot2d.loudspeakers(array.x, array.n, selection * array.a, size=0.15)
plt.close()
Define a function which will update im
for each frame of the animation.
def update_frame_pressure(t):
p = sfs.td.synthesize(
d, selection, array, secondary_source, grid=grid, observation_time=t)
im.set_array(p)
return [im]
Put everything together to create an animation.
ani = animation.FuncAnimation(
fig, update_frame_pressure, frames=time_stamps,
interval=interval, blit=True)
"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)" |
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.
After creating the GIF file, you could also include it in a Markdown cell like this:

BTW, why are you specifying fps
here and not above when using to_jshtml()
?
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# Save as gif file - This might take a few minutes.\n", |
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.
Whenever I write that something takes a long time, I also try to show how long it actually takes. You could use the %%time
magic here:
%%time
ani.save("wfs-25d-td.gif", writer='imagemagick', fps=10, dpi=200)
I added some ideas in the branch td-wfs-animation-fscom |
Add Jupyter notebook for generating an animation of a synthesized sound field.