In [1]:
from __future__ import print_function, division
import lambdasim as l
import shapelib as sh
import os
from IPython.display import *
%matplotlib inline
A Simulation is defined by a regular matrix and a resolution to match it to real-world dimensions. Here we define a simulation space of 5,33m x 3m with a spatial resolution of 6mm and a time resolution of 0.01 ms (the time resolution depends on the propagation time of our medium)
In [2]:
# Create dimension to fit standard video sizes
Ypix = 480
Xpix = int(Ypix * 16/9. +0.5)
Y = 3. # in meters
s = l.Simulation(resolution=Y/Ypix)
s.set_size_in_pixels(Xpix, Ypix)
X, Y = s.size()
wall_y = Y*0.25 # the position of the slit, relative to the size of the canvas
wall_width = 0.03 # the with of the wall, in m (3cm)
source_y = 0.05 # the position of the source, in meters
source_width = X*0.4 # the width of the source (a planar source)
source_freq = 1000 # Hz
source_amp = 0.3 # Pa
slit_width = max(l.acoustics.freq2wavelen(source_freq)/4, 5*s.nodesize)
slit_dist = min(l.acoustics.freq2wavelen(source_freq)*2, source_width*0.9)
print(s)
print("slit width:", slit_width)
We want to work on the real-world dimensions and leave the rasterization of the space as an implementation detail, so that we can increase the resolution when needed, without having to redefine the simulation. That's why all operations are done with "geometries", which have infinite resolution, and only at the end we rasterize it to the underlying matrix (this is done with .wall_from_geometry). Also, since we are working with analytical shapes, it is very easy to calculate dead nodes and angles, which increase both throughput and resolution of the simulation.
In [4]:
wall = sh.box(0, wall_y-wall_width*0.5, X, wall_y+wall_width*0.5)
def makeslit(wall, x, y, width, height=1):
slit = sh.box(x - width*0.5, y-height*0.5, x+width*0.5, y+height*0.5)
wall = wall.difference(slit)
return wall
wall = makeslit(wall, X*0.5 - slit_width*0.5 - slit_dist*0.5, wall_y, slit_width)
wall = makeslit(wall, X*0.5 + slit_width*0.5 + slit_dist*0.5, wall_y, slit_width)
# sidewalls
wall = wall.union(sh.box(0, 0, X*0.5-source_width*0.5, wall_y))
wall = wall.union(sh.box(X*0.5+source_width*0.5, 0, X, wall_y))
s.wall_from_geometry(wall)
sh.geom_plot(wall, yrange=(0, Y))
In [5]:
linesource = sh.line(X*0.5-source_width*0.5, source_y, X*0.5+source_width*0.5, source_y)
source = s.source_from_geometry(linesource, 'sin', amp=source_amp, freq=source_freq)
print(source)
In [6]:
xpix, ypix = s.size_in_pixels()
s.write("twoslit{x}x{y}.sim".format(x=xpix, y=ypix))
s.plot()
This will open the Lambda app with our simulation. For that you need to have the app installed in your system. See https://github.com/gesellkammer/lambda/releases
In [9]:
proc = s.opensim(vis=True, cmap=2, contrast=72)
In [10]:
proc, videopath = s.render_video(duration=40/1000., contrast=76, cmap=2, walls=True, fps=60)
In [21]:
from IPython.display import HTML
HTML("""
<video controls>
<source src="https://dl.dropboxusercontent.com/u/264776/web/lambda/twoslit854x480.webm">
</video>
""")
Out[21]:
In [ ]: