Next post: Computer keyboard as piano keyboard

Doppler Effect Simulation


This is a Doppler effect simulation that creates the sound of particles whizzing past you, in stereo. You, the "observer", are represented by the L and R rectangles. The green numbers represent points along the path of that the particle travels. One specifies the path by moving the position of the numbers by clicking and dragging. If the points are farther apart, the particle travels faster, and if the points are close, the particle moves slower.

It's fun to play with. By clicking the checkbox, a second particle can be added.




The physics are only approximate, because this is an audio project and not a physics project. Each pixel corresponds to 2 meters. The physics is deliberately exaggerated a bit to get a better sounding effect; for example in reality your right and left ear are close, but in this simulation the "R" and "L" observers are fairly far apart. The simulation assumes each particle is producing a loud square wave at a constant pitch.

I was able to write the code quickly. The expression (V / (V + vS)) gives a frequency shift, so if this value is 1.5, the perceieved pitch is 1.5 times higher. It turns out that this frequency shift is very well suited to code. First, I generate many seconds of source audio, say a sine wave at a fixed frequency. Then, I walk through this source audio at the "frequency shift" rate, interpolating between values when needed. So if the "frequency shift" came to 1.3, I would take the 0th, 1.3th, 2.6th, 3.9th, samples from the source audio as the output audio, which results in output audio with a 1.3 times higher pitch. So, the core of the project simplified to this:

positionInSourceAudio = 0.0;
V = 340; //speed of sound
// fill an array named "sourceAudio" with a simple square wave
// for each timestep:
// move x and y
// find distance between particle and observer
distance = Math.Sqrt((x - xMe) * (x - xMe) + (y - yMe) * (y - yMe));
vS = (distance  -  prevdistance) / dt;
freqShift = (V / (V + vS));
amplitude = scale * (1 / (distance * distance));
for (int i = 0; i < dt * sampleRate; i++)
    outputAudio[index+i] = amplitude * interpolatedValue(sourceAudio, positionInSourceAudio); 
    positionInSourceAudio += freqShift;

The source is on GitHub here, under the GPLv3.