Doppler Effect with Arduino DUE


The Doppler Effect, both the electromagnetic/optical and acoustical, are mostly observed at high frequencies and high speeds of sender and/or receiver but they really show up at any speeds (unless zero).

There are many web pages about the theory of the Doppler Effect, so I am not going to add another one.

It is a nice challenge to demonstrate this effect at speeds of human movements (one foot per second should fit) and frequencies handled by standard devices. First experiments proved: it cannot be shown with an Arduino UNO or Arduino MEGA; the frequency resolution of the FFT must exceed the shift in frequency you want to detect. So you need a certain amount of samples, each sample will need to be stored as real and imaginary floating point value each taking 8 bytes of RAM.

With an Arduino DUE, you have enough RAM and pretty much performance. But to generate a signal to be transmitted you need the tone() function. And they forgot to implement it for the DUE. So you have to search for a replacement. After some search you will come across a posting from Palliser giving you a square wave signal at Pin-2 (no other choice).

To get a visible effect, you should transmit a very high frequency. But devices for ultrasonic are rare and expensive. So transmitting 20 kHz has the advantage it won't disturb nobody (except your dog or some bats) and your ordinary piezo speaker and a cheap electret condenser microphone will do the job pretty well.

But unfortunately, when you setFrequencytone(20000) your FFT gives you a peak at 20508 Hz which will be confirmed by your cymometer/frequency counter. So keep in mind to subtract the proper value from your received signal. Now connect a piezo speaker to Pin-2 and an electret condenser microphone via a small preamplifier to A0 to get readings with analogRead().

In your loop(), just sample 211 analogRead() values, perform an FFT, get the maximum peak (avoid getting the DC peak), subtract the frequency that you have been transmitting, and print the shift value to the Serial Plotter (IDE 1.6.8). The result might look like this:


As you can see, there have been slower and faster movements of the speaker in both directions.

And, if I did the math properly a speed of either the mic or the speaker of ten inchs per second results in a frequency shift of about 25 Hz.


Any kind of those cheap electret microphones will do. And whatever piezo is around. We are not going for HiFi.


The mic amplifier and the 3.5mm audio jacks fit nicely on a protoboard on top of the Arduino DUE.


The amplifier can be kept very simple. Any kind of Opamp will do. Adjust the potentiometer in order to obtain about 2.5 V DC at the output.

The source:

#include "PlainFFT.h" // http://www.arduinoos.com/2010/10/fast-fourier-transform-fft-cont-5/
#include "tone.h"     // https://forum.arduino.cc/index.php?topic=363557.0

PlainFFT FFT = PlainFFT(); //* Create FFT object *
const byte sensorPin = A0;
const byte N = 11;
const int samples = 1 << N;
double vReal[samples];
double vImag[samples];
int f0 = 20000;
int f1 = 20508;
long dt;

void setup() {
  Serial.begin(115200);
  Serial.println(__FILE__);
  analogReadResolution(10);
  long t1 = micros();
  long t2 = micros();
  dt = t2 - t1;
  configureToneTimer();
  setFrequencytone(f0);
}

void loop() {
  // get the samples:
  long t1 = micros();
  for (int i = 0; i < samples; i++) {
    vReal[i] = analogRead(sensorPin);
    vImag[i] = 0;
    delayMicroseconds(15);
  }
  long t2 = micros();
  float samplingFrequency = samples * 1E6 / (t2 - t1 - dt);  
  float f = 1E6 / (t2 - t1 - dt);  
  FFT.Compute(vReal, vImag, samples, FFT_FORWARD); // Compute FFT
  FFT.ComplexToMagnitude(vReal, vImag, samples);   // Compute magnitudes
  double x = FFT.MajorPeak(vReal, samples, samplingFrequency);
  Serial.println(x-f1);
}




contact: nji(at)gmx.de