How to find maximums or peaks of sound

Hi guys,

I have an analog signal going to the arduino and I need to detect peaks. My project is about detecting values of noise in a room. I connected microphone with an amplifier and this signal is going to my Arduino, the problem is, that analogRead is giving me ,,random" values varying a lot. I know that sound is a wave so I need to detect peaks so I can work with actual value of the sound, but I don´t know how. Any ideas? Thanks a lot if anyone could help me.

sketch_nov02a.ino (923 Bytes)

Your code samples the audio signal for an extremely brief instant, about three times a second.

Consequently, it is extremely unlikely that you will accidentally capture any interesting peaks in the audio.

 hodnota = analogRead(mic);
  Serial.println(hodnota);
  Serial.println();
  delay (300);

In order to improve on this, you need to collect many samples as fast as possible, store them in an array and then analyze the array for peaks later.

Example of collecting 250 data points, one point about every 110 microseconds:

int sound_value[250];
for (byte i=0; i<250; i++) sound_value[i]=analogRead(mic);

Google "peak detection algorithm" to learn how to detect peaks in the data.

Zero point (no audio) is also undefined.
Remove C3, and connect the output of the amplifier directly to A0.
Then you should have an A/D value of ~512 without sound.

You could use two variables. A 'minimum' and a 'maximum'.
Then sample for a certain amount of time, and update those two values on-the-go.
Subtract min/max, to find the peak/peak value.
Leo..

Untested example.
Leo..

int rawValue, minimum, maximum, peakValue;
int threshold = 100; // sensitivity

void setup() {
  Serial.begin(9600);
}

void loop() {
  minimum = 0; // reset
  maximum = 0;
  for (int i = 0; i < 500; i++) { // measure
    rawValue = analogRead(A0);
    if (rawValue < minimum) minimum = rawValue; // store min peak
    if (rawValue > maximum) maximum = rawValue; // store max peak
  }
  peakValue = maximum - minimum; // calc difference
  if (peakValue > threshold) { // action
    // do something
  }
  Serial.print("Peak value: ");
  Serial.println(peakValue);
  delay(250); // remove in final code
}

Thanks you guys, but there is few other things I don´t understand so: how do I choose this threshold and how do I choose this time during which I will be finding max, min = how do I know where is the beggining of the new ,,period of sound" . Jremington is collecting 250 data points, Wawa 500, how did you decide these values?

Rather than a microphone you might find it easier to use something like the Sparkfun Sound Detector board which already does the basic integration for you and has an output which follows the overall volume of sound. Because that is a lot slower moving than the actual sound waveform it's easier to deal with. Have a look at SparkFun Sound Detector - SEN-12642 - SparkFun Electronics? and the associated tutorials.

Steve

TeresaH:
how did you decide these values?

Each sample takes about 100usec.
500 samples will capture the full wave of 20Hz.
Leo..

how do I know where is the beggining of the new ,,period of sound"

To do that, one method is to store the data in an array, and search for the peak.

It takes (by default) about 110 microseconds to collect each data point, so record the time in microseconds when you start collecting data, find the array index of the peak and add to the start time 110*(array index of peak).

Define "peaks".

The example given try to sample the wave and detect the highest point of a wave. But when you say "peak" in relation to sound, I'm thinking "volume" or "decibels". The peak of an input wave is not necessarily the same, or is it?

Anyway, for peak detection where you don't care about the rest of the data I'd use a different approach.

Set the ADC in free running mode where it just does conversions as fast as it can, and have it trigger an interrupt every time a conversion is complete.
Have the ISR read the ADC register, and see if the value in this register is higher than the previous recorded value. If so, record that as new value. This way you record the peak value (and only the peak value - the rest of the wave is discarded).
Then after a certain time has passed you can record this peak value into another array and reset it to zero, to start measuring the next peak. If you like you can set up a timer interrupt for this, and it is basically running in the background.