clap detect

Hi all I have arduino uno now , and currently I have one small electret microphone amplifier is there a way to determinate voice and clapping by analog value from arduino ?

The code I am using to detect single,double clapping is :

int potPin = 2;   
int ledPin = 13;  
int val = 0;  
int amp = 0;  
int go = 0;  

unsigned long lastClap = 0;
unsigned long nowClap = 0;
unsigned int claps = 0;
#define DOUBLECLAPTHRESHOLD 700

void setup() 
{  
  pinMode(ledPin, OUTPUT);  // declare the ledPin as an OUTPUT  
  Serial.begin(9600);
}  

void loop() 
{ 
  val = analogRead(potPin);  
  amp = (val >= 512) ? val - 512 : 512 - val;  
  
  if (amp > 200) // threshold
  {
    nowClap = millis();
    claps = 1;
    if (nowClap - lastClap < DOUBLECLAPTHRESHOLD) claps = 2;
    lastClap = nowClap;
  }
 delay(30);
 switch(claps)
  {
  case 0:
    digitalWrite(ledPin, LOW);
    break;
  case 1:
    digitalWrite(ledPin, LOW);
    break;
  case 2: 
    digitalWrite(ledPin, HIGH);
    break;
  default:
  digitalWrite(ledPin, LOW);
    break;
  }
 
}

Think it is very difficult, impossible if you want 100%,

You could make a "volume-o-gram"

if sound comes above a threshold, start timing, and log values in an array if sounds drops under the threshold, stop timing

if it was short and has a high peakvolume => clap if it was longer and "flatter" => voice

might be a nice casus for a neural network approach?

Ok,my amplifier give me analog values from 0 to 1024,how should I understand when I am clapping and when I am talking , if I am talking louder then normal then the amplifier will detect it as clapping and vice versa. Maybe I need some algorithm to do this,and I will be very thankfull if someone can give to me ...

mitko290: Ok,my amplifier give me analog values from 0 to 1024,how should I understand when I am clapping and when I am talking , if I am talking louder then normal then the amplifier will detect it as clapping and vice versa. Maybe I need some algorithm to do this,and I will be very thankfull if someone can give to me ...

What you are asking for, to be able to distinguish between a loud voice and a loud clap is something beyond the capabilities of an Arduino, at least in my opinion. By the way are you applying pure audio AC voltages to the analog input pin? I ask because arduino pins cannot safety handle negative voltages and you risk damage to the pin.

Lefty

Yes I am sure... I just want to activate the the whole system only if clap was heard

Maybe I need some algorithm to do this, and I will be very thankfull if someone can give to me …

try this, it is a first coded version of the base algorithm I posted before, might need some tweaking or so

(not compiled or tested…)

#define LOW_THRESHOLD 50
#define HIGH_THRESHOLD 200

#define MAXCLAPSAMPLES 400

int i = 0;
uint8_t array[MAXCLAPSAMPLES+1];

void setup()
{
  Serial.begin(115200);
  Serial.println("Clap detector 0.1");
}

void loop()
{
  // MAKE MEASUREMENT
  int volume = analogRead(A0)/4;   //  gives a range from 0..255, fits in a byte
  int maxVol = 0;
  while (volume > LOW_THRESHOLD && i < MAXCLAPSAMPLES)
  {
     maxVol = max(maxVol, volume);
     array[i++] = volume;
     volume = analogRead(A0)/4;
     // delay(5);
  } 

  // ANALYZE SAMPLES IN ARRAY  (can be extended to much more complex rules)
  if (i > 0) 
  {
    Serial.println("analyzing samples...");
    for (int j=0; j < i; j++)   // dumping samples so you can copy them into Excel
    { 
      Serial.print(array[i]);
      Serial.print(", ");
    }
    Serial.println();

    if (i <= MAXCLAPSAMPLES && maxVol >= HIGH_THRESHOLD) Serial.println("hard clap");
    if (i <= MAXCLAPSAMPLES && maxVol < HIGH_THRESHOLD) Serial.println("soft clap or short voice");
    if (i > MAXCLAPSAMPLES && maxVol >= HIGH_THRESHOLD) Serial.println("hard voice or multi clap");
    if (i > MAXCLAPSAMPLES && maxVol < HIGH_THRESHOLD) Serial.println("soft voice");
  }

  // RESET VARS
  i = 0;
  maxVol = 0;
}

Does it need to distinguish between a clap and a short shout, or just between a clap and normal talking?

If it's the latter, then simply listening for 2 loud sounds wouldn't work, since loud talking could just be constant loud noise.

However, it might work to listen for a loud noise, then for a silence, then a loud noise, then a longer silence, all within a certain period of time from each other. I have a Clapper that plugs into an outlet to control lamps, etc, and it appears to work in this way. (i.e. if I clap, a light turns on at each clap, but if I just say "aaaaaaaaaaaaaaaaa", one light goes on, then turns off.) This means you can still purposely trigger it by making 2 short shouts, but this probably would not end up being a problem. (and a useful feature if both of your hands are broken)

Here is an idea for you: count zero crossings as well as volume.

Use the mike with an amp and connect to analog port.

Read port as fast as possible in a tight loop. You can get about 10K samples per second, which is enuf for this purpose. Every time the value goes from + to - (which you’ll have to bias, so + is > 512, - is < 512), that is a “zero crossing”. Count the number of them. Simultaneously track the average max value, ie, the sound volume.

I believe you will find, with some experimentation, that a clap will produce far higher zero crossings than any voice can do!

(Essentially, zero crossings per second are a very rough estimate of the major frequency of the sound. A clap is white noise, energy at all frequencies, lots of high frequencies, lots of zero crossings. A voice is closer to pure, less high frequencies.) Thus, at same volume level, here is a way to distinguish a clap from vocal sounds.)

Just a thought, idea for experimenting… I built a simple voice recognition system using this method, actually got 90% recognition of digits and letters expressed as “alpha” “bravo” “charlie” etc. On a Z80 in 1990!

Yes I am sure... I just want to activate the the whole system only if clap was heard

Again, you are risking damage to your analog input pin. You should wire the audio signal through a rectifier/filter circuit and then to the analog input pin.

http://en.wikipedia.org/wiki/Envelope_detector

retrolefty:

Yes I am sure…
I just want to activate the the whole system only if clap was heard

Again, you are risking damage to your analog input pin. You should wire the audio signal through a rectifier/filter circuit and then to the analog input pin.

http://en.wikipedia.org/wiki/Envelope_detector

Ok when I measure with my volt meter the amplifier out pin and ground I am receive only positive values - now do I need this rectifier/filter circuit before connect to arduino ?
I am using this amplifier:
http://www.hobbykit.eu/hobbye/h1035.html
And the code I build until now:

// these constants won't change:
int amp = 0 ;
unsigned long lastClap = 0;
unsigned long nowClap = 0;
unsigned int claps = 0;

const int ledPin = 13;      // led connected to digital pin 13
const int electret = 0;  // the amplifier output is connected to analog pin 0


// these variables will change:
int sensorReading = 0;      // variable to store the value read from the sensor pin
int sensorMax = 0;
int sensorMin = 1023;
int threshold;
#define DOUBLECLAPTHRESHOLD 1000

void setup() {
  pinMode(ledPin, OUTPUT); // declare the ledPin as as OUTPUT
  Serial.begin(57600);       // use the serial port
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  while (millis() < 3000) {
    threshold = analogRead(electret);

    // record the maximum sensor value
    if (threshold > sensorMax) {
      sensorMax = threshold;
    }

  }

  // signal the end of the calibration period
  digitalWrite(13, LOW);
  threshold = sensorMax;

}

void loop() {
  // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(electret);    

  if ((sensorReading >= threshold)) {
    Serial.println(sensorReading-threshold); //Will send only positive and absolute values of waveform         
    amp = (sensorReading-threshold);
  }
  if(amp > 200) {
   nowClap = millis();
   claps = 1;
  if (nowClap - lastClap < DOUBLECLAPTHRESHOLD) claps = 2;
  lastClap = nowClap; 
  }
   delay(30);
switch(claps)
  {
  case 1:
    Serial.println("First clap");
    break;
  case 2: 
    Serial.println("Second clap");
    break;
  default:
    break;
  }


  delay(5);
claps = 0;
}

but sometimes its showing first clap,sometimes is showing second claps I want to accurate it now …

Have you checked with mtbiker - http://arduino.cc/forum/index.php/topic,64236.0.html - which also made a clap detector ?

robtillaart: Have you checked with mtbiker - http://arduino.cc/forum/index.php/topic,64236.0.html - which also made a clap detector ?

I already read that ...

BUt have you send him a message for his final code?

robtillaart: BUt have you send him a message for his final code?

off course I did , but he said the final code it is in the forum

ok...

As RetroLefty hinted You need to be tracking the envolope of the sound rather that the raw frequency's them self's. You can get ic's for graphic eq's that split the audio into 7 baud's i think and output 7 envolope curves. You could read these on the analog input pin's. You would want to use all 7. Some analysis using audio editing software and spectrograms of clapping should shed some light on the subject. By comparing this data to the frequency's of your eq ic output's you should be able to come up with an algorithm that at least starts to cut out the frequency's that your not interested in and analyses the envolope curves independently. It will never be 100% though.

The link below shows a screen shot of the audio waveform (44.1K sampling rate, “Amadeus” software for Mac) of me saying “Hello” and me clapping twice, with close ups showing (selected in blue) eactly 20 ms from both. Note the zero crossings, places where the curve crosses the zero line. I count about 22 in the 20 ms of hello, and about 80 in 20 ms of a clap. Here is the link:

https://dl.dropbox.com/u/676415/TT/PT/hello%20and%20clap%20compared.jpg

Note that if you had 20 crossings in 20 ms, that would be about 1 per ms or a tone of about 1,000 Hz, which is about where my voice is. The voice signal has lots of high frequency overtones in it, but as you can see, these manifest as small wiggles on the main almost-sine wave. In other words, the main frequency is very powerful, the overtones weak. Whereas a clap products LOTS of high frequency noise all strong. Easy to see in the pictures.

Zero crossings is a gross approximation of the pitch. Reference:

Also, zero crossings is computationally easy. I suspect something like the following might work. It doesn’t store anything in an array and is computationally easy. It monitors for 10 ms, if the clap was very short it might miss it, so might have to reduce the times thru the for loop and all other numbers. I have not tried this code, just suggesting something like it might work… Good luck!

void waitForClap() {

bool clap;
  
do
  {
  int amp,prev_amp;

  
  prev_amp = analogRead(0) - 512;
  #define sign(x) ( (x>=0) ? +1 : -1 )
  
  int zeroCrossings=0;
  int highAmp=0;
  
  // I estimate this loop will go about 8KHz, thus 80 times is 10 ms
  
  for (int i=0; i<=80; i++)
    {
    amp = analogRead(0) - 512;
    if (sign(amp) != sign(prev_amp)) zeroCrossings++;
    if (abs(amp) > 300) highAmp++;
    }
  
  clap = (highAmp > 15 && zeroCrossings > 20); // all numbers subject to experimentation!
  }
     while (clap = false);
}

retrolefty: What you are asking for, to be able to distinguish between a loud voice and a loud clap is something beyond the capabilities of an Arduino, at least in my opinion.

Lefty

So I would look at doing a fast fourier transform and the look for the different spectrum between a clap and the human voice.