The simulation

Note that when you move the source or change the frequency of the source, it will take a while for the diffraction calculations to update.

I recommend that you keep the source to the left of the wedge if you want to observe the results of the diffraction calculations, as the calculations are done starting to the right of the wedge (you'll see what I mean if you play around with the simulation).

I could make the code much more effective by optimizing things (many times more effective, probably), but I won't do any of that as it's just a proof of concept.

The theory

The specular reflections are calculated by reflecting the source relative to the wedge. The shadowing is self-explanatory.

The diffraction is calculated using the Biot-Tolstoy expressions, using the method presented by Svensson et al (JASA 1999). The simulation spans 1 meter by 1 meters. The wedge spans 1 meter to both sides of the source. The simulation represents a cut plane perpendicular to to the wedge.

The amplitude and phase of the diffracted signal is calculated from the impulse response at many points in space, using the Goertzel algorithm (for a single frequency). The algorithm is implemented server-side, using Python/Numpy.

The calculations are done with some simplifications, to keep the server happy. I haven't validated the results in the simulation thoroughly, small errors could be seen for the few points I tested (most likely due to the simplifications). But the calculation model works; I compared my Python implementation more rigorously with the examples in the paper by Svensson.

The implementation

A lot of things are calculated using the shaders which definitely should not be calculated using them. If you delve deeper into the code (esp. the shaders), you will most definitely encounter quite a few ugly things. But the simulation runs happily on my computer(s), so I'm happy.

Each time you move the source or change the frequency, the contribution of the diffracted signal is calculated for a polar grid, spanning 32 x 32 points (it extends quite a bit outside the visible view). The origin of the grid is at the edge of the wedge. The calculations are done server-side, and fetched one data point at a time using jQuery/ajax/JSON. This makes the calculations really slow, but it's partly also because I don't want to strain the server too much. I mainly wanted to test how these types of calculations can be done using Django.

This diffraction data is passed to the shaders using a 2D texture, with two bytes ("red" and "green") representing the amplitude of the signal and one byte ("blue") representing the necessary phase data.

WebGL can handle linear interpolation for textures automatically, so the data is interpolated nicely in-between the data points.

In this post, I'll use a feedforward comb filter to explain interference between two sources at some specific location.

The comb filter shows the frequency response of the system. If we have two sources emitting the same signal in space, they will attenuate and amplify certain frequencies at some location according to the frequency response of the comb filter.

The simulation

The red dot represents an ideal microphone in space. Click anywhere inside the simulation to move the sources and the microphone around (you need to click in three separate locations). You can adjust the frequency of the sources using the slider to the right.

How it works

The simulation is done using WebGL shaders, which makes the simulation run really smoothly. The two sources are summed for each pixel in each frame, which gives a nice visual representation of their interference in a 2D plane.

The simulation has the following properties:

The sources have identical phases and frequencies.

2000 seconds in the simulation represents 1 second.

The size of the box is 1 meter by 1 meter.

The sound sources are modeled as cylindrical waves, as per , with for both sources.

The initial delay from the nearer source is left out of the diagram of the comb filter, but it could be added without any change in the magnitude of the response.

The frequency response for a point is calculated directly from the frequency response of the depicted comb filter.